c++ - 为什么在宏中使用看似毫无意义的 do-while 和 if-else 语句?

标签 c++ c c-preprocessor c++-faq

在许多 C/C++ 宏中,我看到宏的代码被包裹在一个看似毫无意义的 do while 循环中。以下是示例。

#define FOO(X) do { f(X); g(X); } while (0)
#define FOO(X) if (1) { f(X); g(X); } else

我看不到 do 而 正在做什么。为什么不直接写这个呢?

#define FOO(X) f(X); g(X)

最佳答案

do ... whileif ... else 是为了做到这一点 宏后面的分号总是意味着同样的事情。比方说你 有类似你的第二个宏的东西。

#define BAR(X) f(x); g(x)

现在,如果您要在 if ... else 语句中使用 BAR(X);,其中 if 语句的主体未包含在大括号中,你会得到一个糟糕的惊喜。

if (corge)
  BAR(corge);
else
  gralt();

上面的代码会展开成

if (corge)
  f(corge); g(corge);
else
  gralt();

这在语法上是不正确的,因为 else 不再与 if 相关联。在宏中用大括号括起来并没有帮助,因为大括号后面的分号在语法上是不正确的。

if (corge)
  {f(corge); g(corge);};
else
  gralt();

有两种方法可以解决此问题。第一种是在宏中使用逗号对语句进行排序,而不会剥夺它像表达式一样的能力。

#define BAR(X) f(X), g(X)

上面版本的bar BAR把上面的代码展开成下面的代码,语法正确。

if (corge)
  f(corge), g(corge);
else
  gralt();

如果你有一个更复杂的代码体而不是 f(X) 需要放在它自己的 block 中,例如声明局部变量,这不起作用。在最一般的情况下,解决方案是使用像 do ... while 这样的东西来使宏成为一个使用分号而不会混淆的单个语句。

#define BAR(X) do { \
  int i = f(X); \
  if (i > 4) g(i); \
} while (0)

你不必使用 do ... while,你也可以用 if ... else 做一些事情,虽然当 if ... elseif ... else 内部展开它会导致“dangling else”,这可能会使现有的悬空 else 问题更难找到,如下面的代码。

if (corge)
  if (1) { f(corge); g(corge); } else;
else
  gralt();

关键是在悬挂分号错误的上下文中用完分号。当然,此时可以(并且可能应该)争辩说,将 BAR 声明为实际函数而不是宏会更好。

总而言之,do ... while 可以解决 C 预处理器的缺点。当那些 C 风格指南告诉你放弃 C 预处理器时,这就是他们担心的事情。

关于c++ - 为什么在宏中使用看似毫无意义的 do-while 和 if-else 语句?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/154136/

相关文章:

c++ - #define 指令有多个替换?

C++模板特化问题

c++ - C++中构造函数和析构函数的内联用法

c - g-wan 更新 servlet

c - 无法用C计算。你如何用C计算?

c++ - 如何使用 Doxygen 注释生成的代码

c++ - 捕获的 Lambda 函数性能影响

c++ - 类的模板参数也是模板参数

c - 迭代 argv[] 会产生段错误

c - 宏如何返回指向未对齐值的对齐指针?