do{...}while(0)的常见用法

去年第一次遇到 do{...}while(0) 的用法,当时以为是那个项目作者的个人习惯,今年开始阅读大量其他开源项目后,发现这种用法很常见,遂查阅资料,现总结如下:

0x01 辅助定义复杂宏,避免引用时出错

看下面这个宏:

#define DO_SOME_WORK() \
    func1();    \
    func2();

本意是通过调用 DO_SOME_WORK() ,来执行 func1() 和 func2() 两个函数。

按照我们习惯的调用方法:

if ( a > 0 )
    DO_SOME_WORK();

实际上展开后是:

if ( a > 0 )
    func1();
func2();

显示不符合我们的预期,如果我们在宏定义时加上 {...} 呢?也是不行,这样展开会是:

if ( a > 0 )
{
    func1();
    func2();
}

这时 do{...}while(0) 就派上用场了:

#define DO_SOME_WORK() \
    do {             \
        func1();    \
        func2();    \
    } while (0)

0x02 避免使用 goto

有时我们会想要在函数内部做些收尾工作,比如说我们在创建一个线程池时,需要多次分配内存的操作,任何一次失败我们都希望 goto 到一个统一的释放已分配内存的任务。

但是 goto 不符合软件工程的结构化,且会破坏指令流水线的效率,所以不提倡使用,这时可以用 go{...}while(0) 配合 break 来实现目的。

下面是一个例子:

使用 goto :

int foo()
{
    somestruct* ptr = malloc(...);
 
    dosomething...;
    if(error)
    {
        goto END;
    }
 
    dosomething...;
    if(error)
    {
        goto END;
    }
    dosomething...;
 
END:
    free(ptr);
    return 0;
 
}

使用 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,原有的收尾工作放在“循环”外。

0x03 定义空宏

有些平台上不允许定义空宏,这是可以这样做:

#define EMPTYMACRO do{}while(0)

标签: Linux/C

精彩评论
  1. 林木 林木

    学习了,向大神学习

    1. 岁月催人老,脱坑要趁早。还是远离C/C++比较好

      1. 林木 林木

        不不不,我要向大神多多学习。

发表评论: