do...while(0)在宏定义中的用法

在Linux内核和其他一些开源的代码中,经常遇到下面的代码:

do{
    ...
}while(0)

其用法体现在如下几个方面:

1.辅助定义复杂的宏,避免引用的时候出现错误:

#define
DOSOMETHING()\
foo1();\
foo2();
以上宏定义的意思是当调用DOSOMETHING()的时候,函数foo1()和foo2()都会被调用

当如果你如此调用

if(a>0)
DOSOMETHING();
因为宏在预定义的时候会直接被展开,调用的时候就会被展开变成如下调用

if(a>0)
   foo1();
foo2();
这里便出现问题:

无论a是否大于0,foo2()都会被调用。


这里还有一个问题,如果将foo1()和foo2()用{}包起来可以么?

我们在写代码的时候都习惯在语句右面加上分号,如果在宏中使用{},代码里就相当于这样写了:“{...};”,展开后就是这个样子:

if(a>0)
{
     foo1();
     foo2();
};
这样甚至不会被编译通过:

所以出现如下写法:

#define DOSOMETHING()
             do{
                  foo1();
                  foo2();
             }while(0)
...

if(a>0)
   DOSOMETHING();
...
这样,宏被展开后,才会保留初始的语义。GCC提供了 Statement-Expressions 用以替代do{...}while(0); 所以你也可以这样定义宏:

#define DOSOMETHING()
({
    foo1();
    foo2();
})
2.避免使用goto对程序流进行统一的控制

我们经常在一些函数return前做一些收尾的工作,比如fee掉一块malloc出的内存,goto一直是比较简便的做法

int foo()
{
     somestruct *ptr = malloc(...);
     dosomething...;
     if(error)
     {
          goto END;
     }
     dosomething...;
     if(error)
     {
          goto END;
     }
END;
     free(ptr);
     return 0;
}
goto不符合软件工程的结构化,这时候使用do...while(0).

int foo()
{
     somestruct *ptr = malloc(...);
     do{
          dosomething...;
          if(error)
          {
                break;
          }
          dosomething...;
          if(error)
          {
                break;
          }
    }while(0);
    free(ptr);
    return 0;
}
这里将函数主体使用do()while(0)包含起来,使用break来代替goto,后续的处理工作在while之后,就能够达到同样的效果。

3.避免if else 不匹配

#define PRINT_STRING(isDoc)
             if(isDoc)
                printDoc();
调用时候会出现下面情况

bool isReady = false;
        bool isDoc = true;
        if(isReady)
           PRINT_STRING(isDoc);
        else
          doOtherThing();
则展开后为下面这样

bool isReady = false;
        bool isDoc = true;
        if(isReady)
             if(isDoc)
                    printDoc();
             else
                    doOtherThing();
出现if else不匹配

4.避免空宏引起的warning

内核中由于不同架构的限制,很多时候会用到空宏,在编译的时候,空宏会给出warning,为了避免这样的warning,就可以使用do{}while(0)来定义空宏:

#define EMPTYMICRO
do{}while(0)

5.定义一个单独的函数块来实现复杂的操作:

当你的功能很复杂,变量很多你又不愿意增加一个函数的时候,使用do{}while(0);,将你的代码写在里面,里面可以定义变量而不用考虑变量名会同函数之前或者之后的重复。 







  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值