do{...}while(0)的意义和用法

On October 9, 2012, in C语言, 语言学习, by sponge

linux内核和其他一些开源的代码中,经常会遇到这样的代码:

do{
 ...
}while(0)

这样的代码一看就不是一个循环,do..while表面上在这里一点意义都没有,那么为什么要这么用呢?

实际上,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();
};

这样甚至不会编译通过。所以,很多人才采用了do{...}while(0);

#define DOSOMETHING() \
        do{ \
          foo1();\
          foo2();\
        }while(0)\
    
...
 
if(a>0)
    DOSOMETHING();
 
...

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

#define DOSOMETHING() ({\
        foo1(); \
        foo2(); \
})

http://www.spongeliu.com/
2、避免使用goto对程序流进行统一的控制:

有些函数中,在函数return之前我们经常会进行一些收尾的工作,比如free掉一块函数开始malloc的内存,goto一直都是一个比较简便的方法:

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

由于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;
 
}

这里将函数主体使用do()while(0)包含起来,使用break来代替goto,后续的处理工作在while之后,就能够达到同样的效果。

 

3、避免空宏引起的warning

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

#define EMPTYMICRO do{}while(0)

 

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

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

anyShare分享到:
          
Tagged with:
 

14 Responses to “do{...}while(0)的意义和用法”

  1. nonoob says:

    2.个人感觉java中的break 的方式对于控制流解决较好
    4.如果只使用{……}而不用do{……}while(0);也有同样的效果吧?

  2. nmsoccer says:

    这个~~ 碉堡了~~感谢楼主

  3. CJ says:

    1、避免GOTO而使用do while不可理喻!滥用GOTO才是魔鬼,没有明白为什么goto不可取才会作出这样的决定吧。用一个无厘头的do while只会使程序更加难以理解。不足取!

    2、有一大段的功能(function)代码为什么不考虑抽象出一个函数(function)?这样得过且过使得程序失去了重构的最佳时机。不提取出一个函数也就算了,竟然还加了一个do while!?同理为什么不能用if true block?此法实不足取!如果要避免函数调用的开销,完全可以交由编译器的inline优化嘛

  4. CH says:

    在gcc 4.4.7中,使用{}将foo1()和foo2()包起来是可行的,分号当作是一个无操作语句,不知道博主是什么环境实验的?

  5. Georgianna says:

    Webmaster do you want unlimited content for your blog?

    Type in google:
    Stottai's Rewriter

  6. Karin says:

    This blog is really cool. I have bookmarked it.
    Do you allow guest post on your blog ? I can write hi quality articles for
    you. Let me know.

  7. 日本超人気スーパーコピーブランド時計激安通販専門店
    2017年最高品質時計コピー、国際ブランド腕時計コピー、
    業界唯一無二.世界一流の高品質ブランドコピー時計。

  8. Maha Store says:

    [...] Maha Pharma Maha Pharma Maha Pharma Maha Pharma Maha Pharma Maha Pharma Maha Pharma Maha Pharma Maha Pharma Maha Pharma Maha Pharma Maha Pharma Maha Pharma Maha Pharma Maha Pharma Maha Pharma Maha Pharma [...]

Leave a Reply

Note: Commenter is allowed to use '@User+blank' to automatically notify your reply to other commenter. e.g, if ABC is one of commenter of this post, then write '@ABC '(exclude ') will automatically send your comment to ABC. Using '@all ' to notify all previous commenters. Be sure that the value of User should exactly match with commenter's name (case sensitive).