将宏扩展为无代码:"do {} while (0)" 或 "while (0) {}"
Expand macro to no code: "do {} while (0)" or "while (0) {}"
在我的代码中,我使用了一个宏,它应该生成一个日志条目,或者根据一些编译标志它不应该:
#ifdef SOMETHING
#define LOG(a) printf ("%s", a)
#else
#define LOG(a) while (0) {}
#endif
这段代码运行良好,但是当我在互联网上查看时,我只看到有人在使用
#define LOG(a) do {} while (0)
而不是
#define LOG(a) while (0) {}
这两种方法等效吗?我应该更喜欢一个吗?
它们的不同之处在于
do {} while (0)
语句末尾需要分号,而
while (0) {}
不会。
所以,当你写
LOG ("Some text\n");
第一个扩展到
do {} while (0);
这是一条语句,但随着第二条语句扩展为
while (0) {};
这是两个语句,while (0) {}
和 ;
(这是一个有效的语句)。
当您将它与 if
结合使用时,这很重要。我你写这样的东西:
if (1)
LOG ("Condition is true\n");
else
LOG ("Condition is false\n");
使用 while (0) {}
方法可以扩展到
if (1)
while (0) {};
else
while (0) {};
相当于
if (1)
while (0) {}
;
else
while (0) {}
;
这不会编译,因为 else
没有相应的 if
。
因此,您应该更喜欢 do {} while (0)
方法以获得更好的兼容性。此外,它更地道。
do {} while (0)
和 while (0) {}
并非在所有上下文中都等效,例如,在后一种情况下,宏的用户自然会在末尾添加语法上不必要的分号,以便:
if( error )
LOG( "ERROR") ;
else
{
...
}
将扩展为:
if( error )
while(0){} ;
else
{
...
}
将 else
与 if
解除关联而失败,因为只有 while(0){}
是有条件的。
还应注意,两者在语法上都不等同于具有类型 int
的 表达式 printf ("%s", a)
,更好的定义是:
#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()
可以在 语句 有效的地方或 表达式 有效的地方使用。 expression 版本应该在可能使用表达式值的情况下使用。 表达式在独立语句中的扩展:
0 ;
是有效的无操作或空语句,但某些编译器或静态分析器可能会针对未使用的表达式发出警告。
常见的空操作习语,例如:
#define LOG(a)
#define LOG(a) ((void)0)
也可以考虑,但都缺乏 句法 等价于替代扩展,因为一个扩展在所有上下文中都有效,而另一个扩展有效。
在我的代码中,我使用了一个宏,它应该生成一个日志条目,或者根据一些编译标志它不应该:
#ifdef SOMETHING
#define LOG(a) printf ("%s", a)
#else
#define LOG(a) while (0) {}
#endif
这段代码运行良好,但是当我在互联网上查看时,我只看到有人在使用
#define LOG(a) do {} while (0)
而不是
#define LOG(a) while (0) {}
这两种方法等效吗?我应该更喜欢一个吗?
它们的不同之处在于
do {} while (0)
语句末尾需要分号,而
while (0) {}
不会。
所以,当你写
LOG ("Some text\n");
第一个扩展到
do {} while (0);
这是一条语句,但随着第二条语句扩展为
while (0) {};
这是两个语句,while (0) {}
和 ;
(这是一个有效的语句)。
当您将它与 if
结合使用时,这很重要。我你写这样的东西:
if (1)
LOG ("Condition is true\n");
else
LOG ("Condition is false\n");
使用 while (0) {}
方法可以扩展到
if (1)
while (0) {};
else
while (0) {};
相当于
if (1)
while (0) {}
;
else
while (0) {}
;
这不会编译,因为 else
没有相应的 if
。
因此,您应该更喜欢 do {} while (0)
方法以获得更好的兼容性。此外,它更地道。
do {} while (0)
和 while (0) {}
并非在所有上下文中都等效,例如,在后一种情况下,宏的用户自然会在末尾添加语法上不必要的分号,以便:
if( error )
LOG( "ERROR") ;
else
{
...
}
将扩展为:
if( error )
while(0){} ;
else
{
...
}
将 else
与 if
解除关联而失败,因为只有 while(0){}
是有条件的。
还应注意,两者在语法上都不等同于具有类型 int
的 表达式 printf ("%s", a)
,更好的定义是:
#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()
可以在 语句 有效的地方或 表达式 有效的地方使用。 expression 版本应该在可能使用表达式值的情况下使用。 表达式在独立语句中的扩展:
0 ;
是有效的无操作或空语句,但某些编译器或静态分析器可能会针对未使用的表达式发出警告。
常见的空操作习语,例如:
#define LOG(a)
#define LOG(a) ((void)0)
也可以考虑,但都缺乏 句法 等价于替代扩展,因为一个扩展在所有上下文中都有效,而另一个扩展有效。