do{…}while(0) 的秒用
在linux内核代码中,有这样的宏定义:
#define DUMP_WRITE(addr,nr) do{ memcpy(bufp,addr,nr); bufg+=nr; }while(0)
这个宏定义意味着引用这个宏操作时会执行循环体一次,但为什么要定义成这样的怪形式呢?
我们看看其他几种形式的宏定义:
#define DUMP_WRITE(addr,nr) memcpy(bufp,addr,nr); bufp+=nr;
这种宏定义行不行?
我们把这个宏放到一个语境中:
if (addr)
DUMP_WRITE(addr,nr);
else
do_something_else();
结果发现编译会出错,为什么?
把宏展开,上述语句块变为:
if (addr)
memcpy(bufp,addr,nr); bufp+=nr;
else
do_something_else();
这样就会在if-else语句之间加了一条语句bufp+=nr;形成类似于 if-dosomething-else 的语句。这样else将无法找到与之匹配的 if,所以编译器会报错。
换种引用形式:
if(!addr)
do_something_else();
else
DUMP_WRITE(addr,nr);
这样虽然编译能通过,但是问题会更严重,因为bufp+=nr; 会始终被执行。
到这里,我们可能马上会想到在宏定义中加一个大括号:
#define DUMP_WRITE(addr,nr) {memcpy(bufp,addr,nr); bufp+=nr;}
这样能行吗?我们放到语境中测试下:
if (addr)
DUMP_WRITE(addr,nr);
else
do_something_else();
依然编译出错,为什么呢?
将宏展开之后为:
if (addr)
{memcpy(bufp,addr,nr); bufp+=nr;};
else
do_something_else();
这里在if-else语句中插入了一条空语句:if-空语句-else,同样的编译器也不能为 else 找到与之匹配的 if 语句。所以依然会编译报错。
而使用下面这种格式的宏定义,则完全没问题。
#define DUMP_WRITE(addr,nr) do{ memcpy(bufp,addr,nr); bufg+=nr; }while(0)