do while 在宏定义中的作用

2021-12-10  本文已影响0人  yxibng

CocoaLumberjack 源码, 对宏定义的语句用do while 来包裹,探究一下这么做的原因

#define NSLogDebug(frmt, ...) do{ if(DD_DEBUG) NSLog((frmt), ##__VA_ARGS__); } while(0)

使宏调用表现得和正常代码一样

在c/c++/oc 中,正常的代码以;结尾, 如果看到一个不以;结尾的代码,会觉得很奇怪,为啥没报错?

doSomething(1) ;
DO_SOMETHING_ELSE(2)  // <== Hey? What's this?
doSomethingElseAgain(3) ;

用户期待在代码结尾缺少;的时候,编译器能正常报错。

所以理想的宏调用应该是, 用户自己在宏语句后添加;

doSomething(1) ;
DO_SOMETHING_ELSE(2);
doSomethingElseAgain(3) ;

产出合法代码

单条宏包含多个语句,在没有{}if 语句被调用,导致if 语句的范围覆盖出问题

#define MY_MACRO(x) f(x) ; g(x)

if(bIsOk)
   f(42) ; g(42) ; // was MY_MACRO(42) ;

如果用{}来包裹, 多了一个;

#define MY_MACRO(x) { f(x) ; g(x) ; }

if(bIsOk)
   { f(42) ; g(42) ; } ; // was MY_MACRO(42) ;

如果if后还有else

#define MY_MACRO(x) { f(x) ; g(x) ; }

if (true)
    MY_MACRO(42);
else
    NSLog(@"xxx");

宏展开后 else 前面多了一个; 语法错误

if (bIsOk)
    { f(42) ; g(42) ; };
else
    NSLog(@"xxx");

合法化代码,作用域保护

看下面的宏定义

#define MY_MACRO(x) int i = x + 1 ; f(i) ;

在以下函数调用中出问题

void doSomething()
{
    int i = 25 ;
    MY_MACRO(32) ;
}

上面的代码展开后, 编译出错

void doSomething()
{
    int i = 25 ;
    int i = 32 + 1 ; f(i) ; ; // was MY_MACRO(32) ;
}

使用do while来包裹

do
{
    // code
}
while(false) ;

好处

  1. 会创建一个作用域来包裹代码块
  2. 结尾需要一个;
  3. 编译器会对条件确定为false情况的do while在编译时优化
#define MY_MACRO(x)                                  \
do                                                   \
{                                                    \
    const int i = x + 1 ;                            \
    f(i) ; g(i) ;                                    \
}                                                    \
while(false)

void doSomething(bool bIsOk)
{
   int i = 25 ;

   if(bIsOk)
      MY_MACRO(42) ;

   // Etc.
}

展开后

void doSomething(bool bIsOk)
{
   int i = 25 ;

   if(bIsOk)
      do
      {
         const int i = 42 + 1 ; // was MY_MACRO(42) ;
         f(i) ; g(i) ;
      }
      while(false) ;

   // Etc.
}

优化后

void doSomething(bool bIsOk)
{
   int i = 25 ;

   if(bIsOk)
   {
      f(43) ; g(43) ;
   }

   // Etc.
}

参考:
Why use apparently meaningless do-while and if-else statements in macros?
内联函数 —— C 中关键字 inline 用法解析

上一篇 下一篇

猜你喜欢

热点阅读