Andrey Tarasevich 提供了以下解释:
- 在 Google 网上论坛上
- 在 bytes.com 上
[对格式进行了细微更改。在方括号[]
] 中添加了括号注释。
使用 'do/while' 版本的整个想法是制作一个将扩展为常规语句而不是复合语句的宏。这样做是为了使函数式宏的使用与所有上下文中普通函数的使用一致。
考虑以下代码草图:
if (<condition>)
foo(a);
else
bar(a);
wherefoo
和bar
是普通函数。现在假设您想foo
用上述性质的宏 [named CALL_FUNCS
] 替换 function:
if (<condition>)
CALL_FUNCS(a);
else
bar(a);
现在,如果您的宏是按照第二种方法(只是{
and }
)定义的,则代码将不再编译,因为“真正的”分支if
现在由复合语句表示。当你;
在这个复合语句之后放一个时,你完成了整个if
语句,从而孤立了else
分支(因此编译错误)。
解决此问题的一种方法是记住不要放在;
宏“调用”之后:
if (<condition>)
CALL_FUNCS(a)
else
bar(a);
这将按预期编译和工作,但这并不统一。更优雅的解决方案是确保宏扩展为常规语句,而不是复合语句。实现此目的的一种方法是按如下方式定义宏:
#define CALL_FUNCS(x) \
do { \
func1(x); \
func2(x); \
func3(x); \
} while (0)
现在这段代码:
if (<condition>)
CALL_FUNCS(a);
else
bar(a);
将编译没有任何问题。
CALL_FUNCS
但是,请注意我的定义与您消息中的第一个版本之间的微小但重要的区别。我没有放
;
after } while (0)
。将 a;
放在该定义的末尾会立即破坏使用“do/while”的全部意义,并使该宏几乎等同于复合语句版本。
我不知道您在原始消息中引用的代码的作者为什么将其;
放在while (0)
. 在这种形式中,两种变体是等价的。使用 'do/while' 版本背后的整个想法是不要将这个 final;
包含在宏中(出于我上面解释的原因)。