当我们定义宏时,do while(0)有什么用?

ama*_*jxq 125 c macros linux-kernel

可能重复:
C/C++宏中的Do-while和if-else语句

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

#define INIT_LIST_HEAD(ptr) do { \
    (ptr)->next = (ptr); (ptr)->prev = (ptr); \
} while (0)
Run Code Online (Sandbox Code Playgroud)

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

SPW*_*ley 139

您可以使用分号跟随它,使其外观和行为更像一个函数.它也适用于if/else子句.

没有while(0),上面的代码将不起作用

if (doit) 
   INIT_LIST_HEAD(x);
 else 
   displayError(x);
Run Code Online (Sandbox Code Playgroud)

因为宏之后的分号会"吃掉"else子句,而上面甚至不会编译.

  • 阿诺解释说.它将扩展为"{(ptr) - > next ...};" 因此,声明后面是第二个声明.如果语法是"if(表达式)语句其他语句".else不会与any关联,因为你会写"if(expression)语句"(一个"{...}"和一个";"语句). (27认同)
  • 但OP的问题就在于此.为什么不只是{(ptr) - > next ...}而不是do {(ptr) - > next ...} while(0);? (6认同)
  • 但请注意,在这种情况下,完全没有必要,因为宏的主体可以更清晰地写成:`(ptr) - > next =(ptr) - > prev =(ptr)`. (6认同)
  • 正如Amo所说,这是一个聪明的技巧,允许宏*是*一个必须以分号结尾的C语句.它使宏的行为与函数调用完全相同,只要语句构造和终止(使用';'). (3认同)

rod*_*ion 43

它允许您将多个语句分组到一个宏中.

假设你做了类似的事情:

if (foo) 
    INIT_LIST_HEAD(bar);
Run Code Online (Sandbox Code Playgroud)

如果在没有封装do {...} while(0);的情况下定义宏,则上面的代码将扩展为

if (foo)
    (bar)->next = (bar);
    (bar)->prev = (bar);
Run Code Online (Sandbox Code Playgroud)

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

编辑:http : //c-faq.com/cpp/multistmt.htmlhttp://developer.apple.com/documentation/DeveloperTools/gcc-4.0.1/cpp/Swallowing-the-Semicolon.html上的进一步说明#吞咽最分号

  • 这并不解释do .. while(0)部分宏,只是使用{}括号. (9认同)