do{...} while(0)

前段时间看公司项目源码时,发现一个很有意思的地方,就是在很多宏函数定义里会出现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就找上门了...

上一篇:JavaScript Patterns 6.2 Expected Outcome When Using Classical Inheritance


下一篇:Json文件出现Expected value at 1:0问题的解决办法