do{...}while(0);的好处

    xiaoxiao2022-07-01  81

            最近阅读libevent源码时,会看到有很多宏定义中使用了do{...}while(0);,看了看一些资料,发现很多源码也会这么写,那么do{...}while(0);的好处是什么呢?这里说一下常见的两种用法:

    保证宏定义的正确使用

             举个例子,如果现在定义如下一个宏:

    #define FUN \ f1(); \ f2(); void f1(); void f2(); int main() { int a = 0; if(a)FUN; return 0; } .....

            从逻辑上来说,这里由于a=0,因此FUN应当不会执行,那么f1和f2都不应该被调用,但是实际上宏的展开结果如下:

    int main() { int a = 0; if(a)f1();f2();; return 0; }

             可以看到,这里不管a是否为0,都会执行f2(),这就和之前所想的不一样了,原因就在于宏定义只是简单的替换,并不会将宏定义作为一个整体。如果使用do{...}while(0);的话,就可以解决这个问题:

    #define FUN \ do \ { \ f1();\ f2();\ }while(0);

              通过do{...}while(0);就直接将f1();f2();作为了一个整体,也就不会出现前面的问题了。

             可能会有疑问:那么直接用{}括号把f1();f2();包起来不就好了么?如果只有if的话自然可以,但是如果还有else就会出问题了:

    #define FUN \ [ \ f1();\ f2();\ ]

             经过宏替换后如下所示:

    int main() { int a = 0; if(a)FUN; else return -1; return 0; } //宏替换结果: int main() { int a = 0; if(a) { f1(); f2(); }; //多了一个分号,后面的else没有配对的if,报错 else return -1; return 0; }

            可以发现,这里的else是没有if与之配对的,编译器会报错。原因就在于前面多了一个分号,如果不要这个分号,那么使用宏的时候就只能像这样:

    if(a)FUN else return -1;

            虽然没有任何语法问题,但是没有分号的一句话,难免会影响阅读,这样的话是不是怪怪的呢?

            因此do{...}while(0);是保证宏定义正确的一种好方法。

    实现goto功能

           再看下面一个例子:

    int main() { ... do something A... ... do something B... printf("done!"); return 0; }

            假设在执行something A的过程中,满足某一条件,你不想再执行后面的something B,直接printf然后返回,那你就需要从A处直接跳转到printf的地方,最容易的就是goto语句了,就不多说了,这里就直接说一下do{...}while(0);在这里如何使用:

    int main() { ... do { do something A... if(cond)break; ... do something B... }while(0); printf("done!"); return 0; }

              当执行A过程中满足了条件cond,那么就直接break,由于A和B都在一个循环体do{}while();里面,因此就会直接跳出 do{}while();执行printf语句了,这样也就通过do{...}while(0);实现了goto的作用。

    最新回复(0)