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 ;
}
相關文章
相關標籤/搜索