宏中 "do {...} while (0)" 和“{...} ((void)0)”之间的实际区别?

Practical differences between "do {...} while (0)" and "{...} ((void)0)" in macros?

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)注意到了吗?

一个区别是您可以将 break 与 #define FOO() do { /* body */ } while (0) 一起使用,但不能与 #define FOO() { /* body */ }(void)0.

一起使用

假设您在一个函数中,例如 hello(),并在 #define FOO() do { /*some device operation */ } while (0) 中执行某些操作,但发生了一些错误,因此您不想继续使用该设备,但函数中还有其他语句hello()你想执行,假设是另一个设备。

所以如果你使用第二条语句那么你会做 return 很可能会退出 hello() 但如果你使用第一个语句你可以愉快地 break 并做一些在另一台设备上以相同的功能运行hello()

实际的区别正是您所指出的。

do { ... } while (0) 习惯用法意味着宏可以在任何 需要语句的上下文中使用。

您建议的习语 { ... } ((void)0) 可以安全地用于 大多数 需要表达式的上下文中 -- 但如果它用于无括号 if声明。

我想不出有什么好的理由使用一个 almost 总是有效的不熟悉的习语,而有一个众所周知的习语 always有效。