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