C语言允许宏带有参数。在宏定义中的参数称为形参,在宏调用中的参数称为实参。对带参数的宏,在调用中不仅要展开,而且要用实参去代换形参。
带参数的宏定义的一般形式为:
在字符串中含有各个形参。
带参数的宏调用的一般形式为:
例如:
在宏调用时,用实参5去代替形参y,经编译预处理宏展开后的语句为:
k =5 * 5 +3 * 5;
例8.2 使用带参数的宏。
解题思路:
定义带参数的宏MAX,用来表示条件表达式“(a>b)? a:b”。
编写程序:
创建一个名为“eg8_2.c”的新文件,在编辑窗口中输入下面的程序代码。
运行结果:
程序说明:
宏名MAX表示条件表达式“(a > b) ? a:b” ,形参a,b均出现在条件表达式中。语句max = MAX ( x, y);为宏调用,实参x,y将代换形参a,b。宏展开后,该语句为“max=(x> y)? x:y; ,用于计算x,y中的较大者。
说明:
(1)带参数的宏定义中,宏名和形参表之间不能有空格出现。例如:#
define MAX(a,b) (a>b)? a:b写为“#define MAX (a,b) (a>b)? a:b”,这种写法将被认为是无参宏定义,宏名MAX代表字符串“(a,b) (a>b)? a:b”。宏展开时,宏调用语句“max = MAX (x , y) ;”将变为“max=(a,b) (a>b)? a:b(x,y);”,这显然是错误的。(www.daowen.com)
(2)在带参数的宏定义中,编译系统不给形参分配内存单元,因此对形参不作类型定义。在宏替换时,只是符号代换,不存在值传递的问题。
(3)宏定义中的形参是标识符,而宏调用中的实参可以是表达式。例如:
宏定义:#define SQ(y) (y) * (y)
宏调用:sq=SQ(a+1);宏调用中实参为a+1,是一个表达式,在宏展开时,用a+1代换形参y,得到如下语句:
sq=(a+1) * (a+1);
(4)带参数的宏定义中,其字符串中的形参用括号括起来和不括起来是不同的。若宏定义改为#define SQ(y) y * y,则宏替换后为“sq=a+1 * a+1;”,运行结果将完全不同。对于宏定义中的字符串不仅应在参数两侧加括号,也应在整个字符串外加括号。
(5)带参数的宏和带参数的函数很相似,但有本质上的不同。
例8.3 带参数的宏和带参数的函数的比较。
编写程序:
创建一个名为“eg8_3_1.c”的新文件,在编辑窗口中输入下面的程序代码。
运行结果:
创建一个名为“eg8_3_2.c”的新文件,在编辑窗口中输入下面的程序代码。
运行结果:
程序说明:
(1)在eg8_3_1.c中,形参为y,函数体中的表达式为( (y) * (y) )。在eg8_3_2.c中,形参也为y,字符串表达式为( (y) * (y))。在eg8_3_1.c中的函数调用为SQ(i++);在eg8_3_2.c的宏调用为SQ(i++),实参也是相同的。从输出结果来看,却大不相同。
(2)在eg8_3_1.c中,函数调用是把实参i的值传给形参y后自增1。然后输出函数值,因而要循环5次,输出1~5的平方值。在eg8_3_2.c中宏调用时,只作代换,SQ(i++)被代换为( (i ++) * (i ++) )。每一次循环时,i完成乘运算后两次自增1,循环三次后i=7,停止循环。
从以上分析可以看出函数调用和宏调用二者在形式上相似,在本质上是完全不同的。
免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。