通过do-while(0)宏定义将代码打包起来,成为一个独立的语法单元,从而不会引起上下文混淆,同时因为绝大多数的编译器都能够识别do{…}while(0)这种无用的循环并进行优化,所以使用这种方法也不会导致程序的性能降低
下面就举几个上下文混淆的例子来说明do-while(0)的好处
例1
先看一个简单的宏
#define SAFE_FREE(p) do {free(p);p=NULL;} while(0)
如果去掉了do... while(0)
即定义SAFE_FREE(p)为
#define SAFE_FREE(p) free(p);p=NULL;
那么下面的代码
if(NULL!=p)
SAFE_FREE(p)
else
//do something
将被展开为:
if(NULL!=p)
free(p);p=NULL;
else
//do something
这样就导致if后面有两条语句,第二条语句总会执行,且else不再与原来的if匹配
所以一般聪明的人在定义宏函数的时候会加上 {}
#define SAFE_FREE(p) { free(p);p=NULL;}
这样貌似解决了问题,可是还是有隐患
因为很多人习惯在C代码最后都加 ;
没有经验的人往往会不管那个SAFE_FREE(p)全是大写,直接在后面加上;
如
if(NULL!=p)
SAFE_FREE(p);
else
//do something
被展开为
if(NULL!=p)
{ free(p);p=NULL;};
else
//do something
多了一个分号,截断了if和else 这样 仍然导致if和else的匹配被破坏的情况
如果使用名家的方法
#define SAFE_FREE(p) do {free(p);p=NULL;} while(0)
那么
if(NULL!=p)
SAFE_FREE(p);
else
//do something
展开为
if(NULL!=p)
do
{ free(p);p=NULL;}
while(0);
else
//do something
好了 这样就一切太平了
书上是这么说,可是我认为虽然采用了
#define SAFE_FREE(p) do {free(p);p=NULL;} while(0) 这样的定义
可是使用者要是突然意识到SAFE_FREE(p)是个宏,然后自作聪明没有在SAFE_FREE(p)后加;
如
if(NULL!=p)
SAFE_FREE(p)
else
//do something
这样展开
if(NULL!=p)
do
{ free(p);p=NULL;}
while(0)
else
//do something
这样while(0)后面没有; 仍然报错!
聪明反被聪明误,只因为还不够聪明。
不过,这样做也是有其道理的。do...while(0)的宏定义后面必须加分号,可以把它当成普通函数来用,这样更贴近C语言的使用习惯。