当第一次遇到do{...}while(0),我是懵的,这是什么操作,为了好看吗?后来发现Linux内核中随处可见啊,大神们这样的操作肯定是有道理的。查询了一些资料,做一下总结。在今后C语言开发中,你也可以放心使用这一技巧。
1. 配合定义复杂的宏,避免宏在预处理展开时出错
举个例子,假设你定义了一个宏:
#define DOSOMETHING() fuc1(); fuc2();
当调用DOSOMETHING()的时候,你希望调用fuc1()和fuc2()来做一些事情。但是当在if语句中调用时,可能会这么写:
if(num > 0)
DOSOMETHING();
预处理展开宏,替换文本如下:
if(num > 0)
fuc1();
fuc2();
这样就出现了问题,fuc2()就不受if语句的控制了,导致程序出错。
可能你会说,宏定义建议把整个表达式用大括号括起来的:
#define DOSOMETHING() {fuc1(); fuc2();}
还是if语句来调用:
if(num > 0)
DOSOMETHING();
else
printf("num<0\r\n");
这样程序编译会报错:

我们查看预处理文件,宏展开是这样子的:

if语句被后面的分号提前结束,else无法与其匹配。而使用do{...}while(0)后就不会出错了,Linux内核中的宏定义很多都是这么用的:

2. 避免定义空的宏时引起warning
一些大型的C工程中,为了兼容不同的架构,或者为了移植方便,都会用到空的宏定义。在编译的时候,编译器会给出警告,为了避免这些warning,我们可以使用do{...}while(0)来定义空的宏:

3. 避免goto语句
在一些函数中,我们可能需要在return语句之前做一些清理工作,很多人不提倡用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;
}
代码可读性和可维护性要比goto语句好多了。
4. 定义单一的函数块来完成复杂的操作
当你的功能复杂,变量很多又不愿增加一个函数的时候,可以将你的代码用do{...}while(0)包裹,在里面可以定义变量而不用考虑变量名会同函数前后重复。当然,为了后续维护方便,不建议这么做。
5. 就是感觉美观好看
对,就是觉得好看,不解释:

网友评论