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