函数宏
函数宏 带参数的宏也被称为"函数宏". 利用宏可以提高代码的运行效率: 子程序的调用需要压栈出栈, 这一过程如果过于频繁会耗费掉大量的CPU运算资源. 所以一些代码量小但运行频繁的代码如果采用带参数宏来实现会提高代码的运行效率.
函数宏的参数是固定的情况
函数宏的定义采用这样的方式: #define name( args ) tokens
其中的args和tokens都是可选的. 它和对象宏定义上的区别在于宏名称之后不带括号.
注意, name之后的左括号(必须紧跟name, 之间不能有空格, 否则这就定义了一个对象宏, 它将被替换为 以(开始的字符串. 但在调用函数宏时, name与(之间可以有空格.
e.g.
#define mul(x,y) ((x)*(y))
注意, 函数宏之后的参数要用括号括起来, 看看这个例子:
e.g.
#define mul(x,y) x*y
"mul(1, 2+2);" 将被扩展为: 1*2 + 2
同样, 整个标记串也应该用括号引用起来:
e.g.
#define mul(x,y) (x)*(y)
sizeof mul(1,2.0) 将被扩展为 sizeof 1 * 2.0
调用函数宏时候, 传递给它的参数可以是函数的返回值, 也可以是任何有意义的语句:
e.g.
mul (f(a,b), g(c,d));
e.g.
#define insert(stmt) stmt
insert ( a=1; b=2;) 相当于在代码中加入 a=1; b=2 .
insert ( a=1, b=2;) 就有问题了: 预处理器会提示出错: 函数宏的参数个数不匹配. 预处理器把","视为参数间的分隔符.
insert ((a=1, b=2;)) 可解决上述问题.
在定义和调用函数宏时候, 要注意一些问题:
1, 我们经常用{}来引用函数宏被定义的内容, 这就要注意调用这个函数宏时的";"问题.
example_3.7:
#define swap(x,y) { unsigned long _temp=x; x=y; y=_tmp}
如果这样调用它: "swap(1,2);" 将被扩展为: { unsigned long _temp=1; 1=2; 2=_tmp};
明显后面的;是多余的, 我们应该这样调用: swap(1,2)
虽然这样的调用是正确的, 但它和C语法相悖, 可采用下面的方法来处理被{}括起来的内容:
#define swap(x,y)
do { unsigned long _temp=x; x=y; y=_tmp} while (0)
swap(1,2); 将被替换为:
do { unsigned long _temp=1; 1=2; 2=_tmp} while (0);
在Linux内核源代码中对这种do-while(0)语句有这广泛的应用.
查看评论 回复