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

144
2个回答

160
你可以在其后添加分号,使其看起来和行为更像一个函数。 它也可以正确地与if/else语句一起使用。 没有while(0),你上面的代码将无法工作。
if (doit) 
   INIT_LIST_HEAD(x);
 else 
   displayError(x);

由于宏后面的分号会“吞掉” else 子句,而上面的代码甚至无法编译。


8
OP的问题仍然存在。为什么不直接写{(ptr)->next ... },而要写do {(ptr)->next ... } while (0);? - joshk0
31
Arno解释说,它会扩展为“{(ptr) - > next ...};”,因此是一个语句后跟一个第二个语句。如果语法是“if(expression)statement else statement”。由于您将编写“if(expression)statement statement”(一个“{...}”和一个“;”语句),因此else将不与任何if相关联。 - Johannes Schaub - litb
3
如Amo所说,这是一种聪明的技巧,它允许一个宏成为一个必须以分号结尾的C语句。这使得宏在语句构建和终止(使用';')方面的行为与函数调用完全相同。 - Eddie
7
然而需要注意的是,在这种情况下所有这些都是完全不必要的,因为宏的主体可以更清晰地写作:(ptr)->next=(ptr)->prev=(ptr) - Jerry Coffin
@JoshK 循环只会执行一次,因为 while(0) 是一个假条件。然而,优化编译器将会去掉 do {stat}while(0) 并且替换成只有 stat,因为它只会发生一次。 - Karim Manaouil

48

它允许你将多个语句组合成一个宏。

假设你做了类似这样的事情:

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


11
这并没有解释宏定义中 do...while(0) 部分的含义,只是讲述了使用 {} 大括号的作用。 - SPWorley
此处所述的 "do {} while (0)" 部分已在该帖子中得到解释,因此该问题是重复的。 - adobriyan
1
SPWorley,adobriyan:实际上,看起来这篇文章的作者添加了解释do {} while (0)的链接。 - Paul Merrill

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接