前段时间看公司项目源码时,发现一个很有意思的地方,就是在很多宏函数定义里会出现do{...} while(0)。
#define ASSERT_ARRAY_EQ(expect, actual) do { /
ASSERT_EQ(sizeof(expect), sizeof(actual)); /
for( size_t i = 0; i < sizeof(expect)/sizeof(int); i++) /
{ /
ASSERT_EQ(expect[i], actual[i]); /
} /
} while(0)
开始的时候百思不得其解,写不写这个循环似乎都只会跑一次,那是不是多此一举呢。后来仔细想了想,这么做在实际的工程项目中的确是非常有用的。
如果不使用do{...} while(0),在非嵌套使用的情况下,使用这个宏是不会出现什么问题的。
/* ...........code............ */
ASSERT_ARRAY_EQ(expected, actual);
/* ...........code............ */
上面这段代码里中间那一行会被宏函数直接替换。
然而,考虑下面这种情况:
if(...)
ASSERT_ARRAY_EQ(expected, actual);
else
...
如果没有do{...} while(0),那么这段代码就会被替换成:
if(...)
ASSERT_EQ(sizeof(expected), sizeof(actual));
for( size_t i = 0; i < sizeof(expected)/sizeof(int); i++)
{
ASSERT_EQ(expected[i], actual[i]);
}
else
...
是不是看出问题了。
那有人就想,为什么不将宏函数直接放在花括号内呢,答案是这样的话可能会带来另一个问题:
if(...)
{
ASSERT_EQ(sizeof(expected), sizeof(actual));
for( size_t i = 0; i < sizeof(expected)/sizeof(int); i++)
{
ASSERT_EQ(expected[i], actual[i]);
}
};
else
...
花括号后面会多一个分号,那你可能会说,我在if语句中使用这个宏函数时不在尾部添加分号不就好了吗,是的,这当然可以。但是,有时编程习惯使然,我们会不自觉的在一行代码后面加上分号,然后bug就找上门了...