带参宏定义
转自:http://blog.csdn.net/swpu_yx32/article/details/52858684
C语言允许宏带有参数。在宏定义中的参数称为形式参数,在宏调用中的参数称为实际参数,这点和函数有些类似。
对带参数的宏,在调用中,不仅要宏展开,而且要用实参去代换形参。
带参宏定义的一般形式为:
#define 宏名(形参列表) 字符串
在字符串中含有各个形参。
带参宏调用的一般形式为:
宏名(实参列表);
例如:
#define M(y) y*y+3*y //宏定义
// Code
k=M(5); //宏调用
在宏调用时,用实参5去代替形参y,经预处理宏展开后的语句为k=5*5+3*5。
其中一定要注意:
1.宏名和形参列表之间一定一定不能有空格 ----宏定义只是简单的字符替换
2.形参之后的,字符串最外面一定一定要带上括号;字符串中的形参也一定要带上括号,括号必不可缺
3、宏定义中do{ }while(0)
第一眼看到这样的宏时,觉得非常奇怪,为什么要用do……while(0)把宏定义的多条语句括起来?非常想知道这样定义宏的好处是什么,于是google、百度一下了。
采用这种方式是为了防范在使用宏过程中出现错误,主要有如下几点:
(1)空的宏定义避免warning:
#define foo() do{}while(0)
(2)存在一个独立的block,可以用来进行变量定义,进行比较复杂的实现。
(3)如果出现在判断语句过后的宏,这样可以保证作为一个整体来是实现:
#define foo(x)
action1();
action2();
在以下情况下:
if(NULL == pPointer)
foo();
就会出现action1和action2不会同时被执行的情况,而这显然不是程序设计的目的。
(4)以上的第3种情况用单独的{}也可以实现,但是为什么一定要一个do{}while(0)呢,看以下代码:
#define switch(x,y) {int tmp; tmp="x";x=y;y=tmp;}
if(x>y)
switch(x,y);
else //error, parse error before else
otheraction();
在把宏引入代码中,会多出一个分号,从而会报错。这对这一点,可以将if和else语句用{}括起来,可以避免分号错误。
【yasi】错就错在宏展开以后,下面用红色标记的多余的一个分号
if(x>y)
{int tmp; tmp="x";x=y;y=tmp;};
else
otheraction();
使用do{….}while(0) 把它包裹起来,成为一个独立的语法单元,从而不会与上下文发生混淆。同时因为绝大多数的编译器都能够识别do{…}while(0)这种无用的循环并进行优化,所以使用这种方法也不会导致程序的性能降低