将宏扩展为无代码:“do {} while (0)”或“while (0) {}”

时间:2021-01-09 12:12:13

标签: c while-loop macros do-while

在我的代码中,我使用了一个宏,它应该根据一些编译标志生成一个日志条目或者不应该生成一个日志条目:

#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) {}

这两种方法等价吗?我应该更喜欢一个吗?

2 个答案:

答案 0 :(得分:6)

do {} while (0)while (0) {} 并非在所有上下文中都是等价的,例如,在后一种情况下,宏的用户自然会在末尾添加一个语法上不必要的分号,以便:

if( error )
    LOG( "ERROR") ;
else
{
    ...
}

将扩展为:

if( error )
    while(0){} ;
else
{
    ...
}

通过将 elseif 分离而失败,因为只有 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() 可以在 statement 有效的地方或 expression 有效的地方使用。 表达式 版本应该在可能使用表达式值的情况下使用。 表达式在独立语句中的扩展:

0 ;

是一个有效的 no-op 或 null 语句,但一些编译器或静态分析器可能会针对未使用的表达式发出警告。

常见的无操作习语,例如:

#define LOG(a)
#define LOG(a) ((void)0)

也可以考虑,但都缺乏与替代扩展的句法等效性,因为一个扩展在其他扩展有效的所有上下文中都有效。

答案 1 :(得分:5)

它们的不同之处在于

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) 方法以获得更大的兼容性。此外,它更地道。

相关问题