1、背景
最近再看一个开源代码的时候,看到很多宏经常这么写的:
#define XXX do{ ... }while(0)
一眼看到的时候就知道这一份代码执行一次,那么do...while还有什么意义呢?在查阅了很多资料之后,才发现,do...while(0)用处太多了,所以在这里总结一下。
2、总结
2.1 辅助定义多语句宏
如果我们定义下列宏:
#define DOSOMETHING() foo1(); foo2();
这个宏的本意是,如果调用DOSOMETHING(),那么就执行foo1()和foo2(),但是如果你这么写:
if(xxx) DOSOMETHING();
那么展开以后:
if(xxx) foo1(); foo2();
不管条件是否满足,foo2()都会执行,那么程序逻辑与本意是不同的。如果采用do..while(0)则可以避免这个问题:
#define DOSOMETHING() do{ foo1(); foo2(); }while(0) if(a>0) DOSOMETHING(); ...
2.2 避免使用goto
有些函数中,在函数return之前我们经常会进行一些收尾的工作,比如free掉一块函数开始malloc的内存,goto一直都是一个比较简便的方法。
int foo() { somestruct* ptr = malloc(...); dosomething...; if(error) { goto END; } dosomething...; if(error) { goto END; } dosomething...; END: free(ptr); return 0; }
由于goto不符合软件工程的结构化,而且有可能使得代码难懂,所以很多人都不倡导使用,那这个时候就可以用do{}while(0)来进行统一的管理。
int foo() { somestruct* ptr = malloc(...); do{ dosomething...; if(error) { break; } dosomething...; if(error) { break; } dosomething...; }while(0); free(ptr); return 0; }
这里将函数主体使用do()while(0)包含起来,使用break来代替goto,后续的处理工作在while之后,就能够达到同样的效果。
2.3 避免空宏引起的warning
内核中由于不同架构的限制,很多时候会用到空宏,在编译的时候,空宏会给出warning,为了避免这样的warning,就可以使用do{}while(0)来定义空宏。
#define EMPTYMICRO do{}while(0)