#define MACRO_NAME(para) do{macro content}while(0)
的格式,总结了以下几个原因:
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();
在把宏引入代码中,会多出一个分号,从而会报错。
//------------------------------------------------
使用do{….}while(0) 把它包裹起来,成为一个独立的语法单元,
从而不会与上下文发生混淆。同时因为绝大多数的编译器都能够识别do{…}while(0)这种无
用的循环并进行优化,所以使用这种方法也不会导致程序的性能降低。
为什么很多linux内核中宏#defines用do { ... } while(0)?
有很多原因:
(Dave Miller的说法):
编译器对于空语句会给出告警,这是为什么#define FOO do{ }while(0);
给定一个基本块(局部可视域),定义很多局部变量;
(Ben Collins的说法):
在条件代码中,允许定义复杂的宏。可以想像有很多行宏,如下代码:
#define FOO(x) \
printf("arg is %s\n", x); \
do_something_useful(x);
现在,想像下面的应用:
if (blah == 2)
FOO(blah);
展开后代码为:
if (blah == 2)
printf("arg is %s\n", blah);
do_something_useful(blah);;
就像你看到的,if仅仅包含了printf(),而do_something_useful()调用是无条件调用。因此,如果用do { ... } while(0),结果是:
if (blah == 2)
do {
printf("arg is %s\n", blah);
do_something_useful(blah);
} while (0);
这才是所期望的结果。
(Per Persson的说法):
像 Miller and Collins指出的那样,需要一个块语句包含多个代码行和声明局部变量。但是,本质如下面例子代码:
#define exch(x,y) { int tmp; tmp=x; x=y; y=tmp; }
上面代码在有些时候却不能有效工作,下面代码是一个有两个分支的if语句:
if (x > y)
exch(x,y); // Branch 1
else
do_something(); // Branch 2
展开后代码如下:
if (x > y) { // Single-branch if-statement!!!
int tmp; // The one and only branch consists
tmp = x; // of the block.
x = y;
y = tmp;
}
; // empty statement
else // ERROR!!! "parse error before else"
do_something();
问题是分号(;)出现在块后面。解决这个问题可以用do{}while(0):
if (x > y)
do {
int tmp;
tmp = x;
x = y;
y = tmp;
} while(0);
else
do_something();
( Bart Trojanowski的说法):
Gcc加入了语句解释,它提供了一个替代do-while-0块的方法。对于上面的解决方法如下,并且更加符合常理
#define FOO(arg) ({ \
typeof(arg) lcl; \
lcl = bar(arg); \
lcl; \
})
近期评论