zoukankan      html  css  js  c++  java
  • 在宏定义Define中使用do{}while(0)的妙处

    转载:https://www.jianshu.com/p/99efda8dfec9

    1.帮助定义复杂的宏以避免错误

    举例来说,假设你需要定义这样一个宏:

    #define DOSOMETHING() foo1(); foo2();
    

    这个宏的本意是,当调用DOSOMETHING()时,函数foo1()和foo2()都会被调用。但是如果你在调用的时候这么写:

    if(a>0)
    	DOSOMETHING();
    

    因为宏在预处理的时候会直接被展开,你实际上写的代码是这个样子的:

    if(a>0)
    	foo1();
    	foo2();
    

    这就出现了问题,因为无论a是否大于0,foo2()都会被执行,导致程序出错。
    那么仅仅使用{}将foo1()和foo2()包起来行么?比如:

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

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

    if(a>0)
    {
    	foo1();
    	foo2();
    };
    

    很明显,这是一个语法错误(大括号后多了一个分号)。
    现在的编译器会自动检测自动忽略分号,不会报错,但是我们还是希望能跑在老的编译器上。

    在没有do/while(0)的情况下,在所有可能情况下,期望我们写的多语句宏总能有正确的表现几乎是不可能的。
    如果我们使用do{...}while(0)来定义宏,即:

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

    这样,宏被展开后,上面的调用语句才会保留初始的语义。do能确保大括号里的逻辑能被执行,而while(0)能确保该逻辑只被执行一次,就像没有循环语句一样

    总结:在Linux和其它代码库里的,很多宏实现都使用do/while(0)来包裹他们的逻辑,这样不管在调用代码中怎么使用分号和大括号,而该宏总能确保其行为是一致的。
    cocos2d-x中大量使用了这种宏定义:

    #define CC_SAFE_DELETE(p) do { if(p) { delete (p); (p) = 0; } } while(0)
  • 相关阅读:
    矩阵树(Matrix-Tree)定理精华
    【面试题flex】关于弹性盒子中 flex: 0 1 auto 的一系列问题
    纯函数-Javascript
    uniapp 低功耗蓝牙使用(经典蓝牙用native.js)
    uniapp截屏
    unicloud数据聚合处理
    uniapp的post请求失效问题
    unicloud链表查询
    uni-id的使用
    坐标转换
  • 原文地址:https://www.cnblogs.com/xuyan123/p/14820010.html
Copyright © 2011-2022 走看看