当第一次遇到do{…}while(0),我是懵的,这是什么操作,为了好看吗?后来发现Linux内核中随处可见啊,大神们这样的操作肯定是有道理的。查询了一些资料,做一下总结。在今后C语言开发中,你也可以放心使用这一技巧。
1
配合定义复杂的宏
举个例子,假设你定义了一个宏:
1#define DOSOMETHING() fuc1(); fuc2();
当调用DOSOMETHING()的时候,你希望调用fuc1()和fuc2()来做一些事情。但是当在if语句中调用时,可能会这么写:
1if(num > 0)
2 DOSOMETHING();
预处理展开宏,替换文本如下:
1if(num > 0)
2 fuc1();
3fuc2();
这样就出现了问题,fuc2()就不受if语句的控制了,导致程序出错。
可能你会说,宏定义建议把整个表达式用大括号括起来的:
1#define DOSOMETHING() {fuc1(); fuc2();}
还是if语句来调用:
1if(num > 0)
2 DOSOMETHING();
3else
4 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)可以实现同样的功能:
1int foo()
2{
3 somestruct *ptr = malloc(...);
4 do
5 {
6 dosomething...;
7 if(error)
8 break;
9 dosomething...;
10 if(error)
11 break;
12 dosomething...;
13 }
14 while(0);
15
16 free(ptr);
17 return 0;
18}
代码可读性和可维护性要比goto语句好多了。
4
定义单一的函数块
当你的功能复杂,变量很多又不愿增加一个函数的时候,可以将你的代码用do{…}while(0)包裹,在里面可以定义变量而不用考虑变量名会同函数前后重复。当然,为了后续维护方便,不建议这么做。
5
就是感觉美观好看
对,就是觉得好看,不解释:

你点的每个赞,我都当成喜欢