【问题标题】:What's the use of do while(0) when we define a macro? [duplicate]定义宏时 do while(0) 有什么用? [复制]
【发布时间】:2009-05-29 00:05:12
【问题描述】:

可能的重复:
Do-While and if-else statements in C/C++ macros
do { … } while (0) — what is it good for?

我正在阅读 linux 内核,发现很多这样的宏:

#define INIT_LIST_HEAD(ptr) do { \
    (ptr)->next = (ptr); (ptr)->prev = (ptr); \
} while (0)

为什么他们使用它而不是简单地在 {} 中定义它?

【问题讨论】:

    标签: c macros linux-kernel


    【解决方案1】:

    你可以在它后面加上一个分号,让它看起来更像一个函数。 那么它也适用于 if/else 子句。

    如果没有 while(0),上面的代码将无法使用

    if (doit) 
       INIT_LIST_HEAD(x);
     else 
       displayError(x);
    

    因为宏后面的分号会“吃掉” else 子句,所以上面的代码甚至无法编译。

    【讨论】:

    • 但是 OP 的问题仍然存在。为什么不只是 { (ptr)->next ... } 而不是 do { (ptr)->next ... } while (0);?
    • arno 解释说。它将扩展为“{ (ptr)->next ... };”因此,一个语句后跟第二个语句。然而,如果语法是“if (expression) statement else statement”。 else 不会与任何 if 相关联,因为您会编写“if (expression) statement statement”(一个“{ ... }”和一个“;”语句)。
    • 正如 Amo 所说,这是一个巧妙的技巧,它允许宏成为必须以分号结尾的 C 语句。它使宏的行为与函数调用完全一样,就语句构造和终止(使用';')而言。
    • 但是请注意,在这种情况下,这完全没有必要,因为宏的主体可以更简洁地写成:(ptr)->next=(ptr)->prev=(ptr)
    • @JoshK 循环只会执行一次,因为 while(0) 是错误条件。但是,优化编译器将摆脱 do {stat}while(0) 并仅替换为 stat,因为无论如何,它只会发生一次。
    【解决方案2】:

    它允许您将多个语句组合到一个宏中。

    假设你做了类似的事情:

    if (foo) 
        INIT_LIST_HEAD(bar);
    

    如果宏的定义没有封装 do { ... } while (0);,上面的代码将展开为

    if (foo)
        (bar)->next = (bar);
        (bar)->prev = (bar);
    

    这显然不是预期的,因为如果 foo 成立,则只会执行第一条语句。无论 foo 是否成立,都会执行第二条语句。

    编辑:http://c-faq.com/cpp/multistmt.htmlhttp://developer.apple.com/documentation/DeveloperTools/gcc-4.0.1/cpp/Swallowing-the-Semicolon.html#Swallowing-the-Semicolon 的进一步解释

    【讨论】:

    • 这里没有解释宏的 do .. while(0) 部分,只是使用了 {} 大括号。
    • do {} while (0) 部分在这篇重复的帖子中进行了解释。
    • SPWorley, adobriyan:实际上,这篇文章的作者似乎添加了解释 do {} while (0) 的链接。
    猜你喜欢
    • 2010-10-29
    • 2012-03-18
    • 2012-03-08
    • 2010-09-20
    • 2016-08-22
    • 2013-10-07
    相关资源
    最近更新 更多