将宏扩展为无代码:“do{}while(0)”或“while(0){}”
在我的代码中,我使用了一个宏,它应该生成一个日志条目,或者它不应该根据一些编译标志:
#ifdef SOMETHING
#define LOG(a) printf ("%s", a)
#else
#define LOG(a) while (0) {}
#endif
这段代码运行良好,但是当我查看 Internet 时,我只看到有人在使用
#define LOG(a) do {} while (0)
代替
#define LOG(a) while (0) {}
这两种方法等价吗?我应该更喜欢一个吗?
回答
do {} while (0)
并且while (0) {}
在所有上下文中都不是等价的,例如,在后一种情况下,宏的用户自然会在末尾添加一个语法上不必要的分号,以便:
if( error )
LOG( "ERROR") ;
else
{
...
}
将扩展为:
if( error )
while(0){} ;
else
{
...
}
由于只有 the是有条件的else
,if
因此将 the与 the分离而失败while(0){}
。
还应该注意的是,两者在语法上都不等同于具有类型的表达式 printf ("%s", a)
,int
更好的定义是:
#ifdef SOMETHING
#define LOG(a) do{printf ("%s", a)} while(0)
#else
#define LOG(a) do{} while(0)
#endif
或者
#ifdef SOMETHING
#define LOG(a) printf ("%s", a)
#else
#define LOG(a) 0
#endif
因此,它LOG()
可以在任何语句有效或表达式有效的地方使用。该表达的版本应该在可能被使用的表达式的值情况下使用。独立语句中表达式的扩展:
0 ;
是有效的 no-op 或 null 语句,但某些编译器或静态分析器可能会针对未使用的表达式发出警告。
常见的无操作习语,例如:
#define LOG(a)
#define LOG(a) ((void)0)
也可以考虑,但都缺乏与替代扩展的句法等效,因为一个扩展在另一个有效的所有上下文中都有效。
回答
他们的不同之处在于
do {} while (0)
语句末尾需要一个分号,而
while (0) {}
才不是。
所以,当你写
LOG ("Some textn");
第一个它扩展到
do {} while (0);
这是一个单一的语句,但第二个它扩展到
while (0) {};
这是两个陈述,thewhile (0) {}
和 the ;
(这是一个有效的陈述)。
当您将它与if
. 我你写的东西是这样的:
if (1)
LOG ("Condition is truen");
else
LOG ("Condition is falsen");
通过这种while (0) {}
方法,这扩展到
if (1)
while (0) {};
else
while (0) {};
这相当于
if (1)
while (0) {}
;
else
while (0) {}
;
这不会编译,因为有一个else
没有相应的if
.
因此,您应该更喜欢这种do {} while (0)
方法以获得更大的兼容性。此外,它更地道。