do while(0)的做用

阅读Mitsuba的代码的时候,发现了一个有意思的地方:函数

#define Log(level, fmt, ...) do { \
        mitsuba::Thread *thread = mitsuba::Thread::getThread(); \
        if (EXPECT_NOT_TAKEN(thread == NULL)) \
            throw std::runtime_error("Null thread pointer"); \
        mitsuba::Logger *logger = thread->getLogger(); \
        if (logger != NULL && level >= logger->getLogLevel()) \
            logger->log(level, m_theClass, \
                __FILE__, __LINE__, fmt, ## __VA_ARGS__); \
    } while (0)

定义了一个Log的宏函数,使用了do{...} while(0)的语法,这里的while中的条件是常量0,上面的代码永远只执行一遍。spa

感受是画蛇添足,作法使人费解。上stack overflow查了下资料。说法不少,我在下面概括两条比较有价值的分析:code

1.就是上面的宏定义中,do{}while(0)的意义:blog

能够先看看Log宏函数如何被使用的:get

Log(EInfo, "The time cost by init is %f",Time_stas::init_time);

Log别看成了一个函数来使用,因此,宏定义替换函数后,须要保证语义不会受到影响。it

假设这样的场景:编译

if( xxxx)class

Log(xxx,"xxxxx");thread

elsetest

xxxx;

若是咱们不使用do{}while(0),使用{}把do{}中的语句括住。

上面的语句就成了:

if(xxxx)

{....};

else

就会出现编译错误。

固然,使用

if(xxxx){

Log(xxx,xxx);

}else

{

}

能够避免上面使用{}的问题。可是,do{}while(0)的确为一种稳健的作法。

 

2.使用do{}while(0),能够使用break语句,从do中跳出,避免goto语句:

int test(int p)
{
  if(p==-1)
   {
       ...//do something
       goto smaecode;
    }  
   if(p ==0)
   {
     ...//do something
     goto smaecode;
   }
   if(p==1)
  {
      ...//do something
     goto smaecode;
  }
samecode:
     ...//do something
    
    return p;

}

在do{}while(0)内部使用break语句能够避免使用goto:

int test(int p)
{
do
{
  if(p == -1)
  {
    ..//do something 
    break;
  }
  if(p==0)
  {
    ..//do something
    break;
  }
  if(p == 1)
  {
    ..//do something
    break;
  }

}while(0);
...//same code
 return p ;
}
相关文章
相关标签/搜索