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