玩命加载中 . . .

你用过do{...}while(0)吗?


当第一次遇到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内核中的宏定义很多都是这么用的:

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. 就是感觉美观好看

对,就是觉得好看,不解释:

代码整洁


文章作者: Tony
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Tony !