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,上面的代码永远只执行一遍。

感觉是多此一举,做法令人费解。上stack overflow查了下资料。说法很多,我在下面归纳两条比较有价值的分析:

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

可以先看看Log宏函数如何被使用的:

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

Log别当作了一个函数来使用,所以,宏定义替换函数后,需要保证语义不会受到影响。

假设这样的场景:

if( xxxx)

Log(xxx,"xxxxx");

else

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

 

posted @ 2015-06-02 16:03  P.wang  阅读(6500)  评论(1编辑  收藏  举报