宏中使用的"do {...} while (0)"和"{...} ((void)0)"之间的实际区别是什么?

9

C语言中常见的做法是使用:

#define FOO() do { /* body */ } while (0)

虽然这样做没问题,但也可以这样做:

#define FOO() { /* body */ }((void)0)

{...}((void)0) 有许多类似的好处:您不会意外合并逻辑,并且需要在行尾加上;,所以像这样奇怪的表达式就不会被忽略:FOO() else {...}

我唯一注意到的区别是它意味着您需要在if语句中使用大括号。

if (a)
    FOO();
else
    BAR();

必须按照以下方式编写:

if (a) {
    FOO();
} else {
    BAR();
}

除了这种怪异的情况外,它似乎运行良好,可以防止使用“do/while”方法时出现相同类型的问题。这两种方法之间是否有显着的差异?换句话说,如果您看到一个使用“{...}((void)0)”的代码库,请问除了已经注意到的一个差异之外,是否有实际原因要转换为使用“do{...}while(0)”?

4
"{ … } (void)0" 这种写法在实践中从未被使用过,即使我之前也从未听说过它。它非常奇怪、毫无意义且没有用处,因为你无法像使用 "do { ... } while (0)" 一样轻松地使用它。"(void)0" 强制转换对于你几乎没有任何有价值的东西,它没有任何好处。 - Jonathan Leffler
6
实际区别 #1:人们知道并认可 do { ... } while(0) 这种变体,而不是其他的。 - Jerry Coffin
5
你指出的差别很大。 - R Sahu
1
@ideasman42:不需要在旁边加分号。请参见http://rextester.com/KJLA9675。 - Ben Voigt
1
同样的示例在C中可以正常工作:http://rextester.com/ADOSK79081 - Ben Voigt
显示剩余10条评论
2个回答

7
实际上,正如您所指出的那样,两种方法有明显区别。
使用“do { ... } while (0)”习惯用语意味着该宏可以在任何需要语句的情况下使用。
您提出的习惯用法“{ ... } ((void)0)”可以安全地在大多数需要表达式的情况下使用,但如果在未加括号的“if”语句中使用,则可能会失败。
当已经有一个众所周知始终有效的习惯用法时,我想不出使用一个陌生的几乎总是有效的习惯用法的好理由。

2
有一种情况它不起作用 - 当您想在宏内使用 break 时,(尽管这并不经常发生)。 - ideasman42

2

一个区别是,你可以在#define FOO() do { /* body */ } while (0)中使用break,但不能在#define FOO() { /* body */ }(void)0中使用。

假设你在一个函数内部,比如说hello(),并且正在执行#define FOO() do { /*some device operation */ } while (0),但是发生了一些错误,所以你不再想继续使用该设备,但是函数hello()中还有其他语句需要执行,比如为另一个设备进行操作。

因此,如果你使用第二个语句,那么你很可能会使用return退出hello(),但是如果你使用第一个语句,你可以愉快地使用break,并在同一个函数hello()中为另一个设备执行某些操作。


2
我并不认为这是一个令人信服的差异。你可以编写代码主体,使其不再是 if (condition) break; …rest of body…,而是写成 if (!condition) { …rest of body… }。这本质上是一个微不足道的变化。你甚至可以在 { …here… } (void)0 版本中嵌入一个 do ... while (0) - Jonathan Leffler
1
@JonathanLeffler 如果有多个if条件怎么办?虽然你总是可以编码,但可读性如何?像这样:http://ideone.com/wfC6Ib - user1627167
1
如果这个链接能说服你的话,可以看一下。但是选择一个而不是另一个的原因之一是,它使阅读和编写变得更加简单。 - user1627167
哪个链接?你是要发布一个示例,还是我误解了你的评论的意思。 - Jonathan Leffler
我考虑使用 {...}((void)0) 的原因之一是它不允许使用 break 语句。 - ideasman42
显示剩余3条评论

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