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 while 正在做什么。为什么不写这个没有它?

#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 做一些事情,尽管 when 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/3752166/

相关文章:

c - C 中的 SMPL preempt()

c - 如何将包含空格的#define 替换列表映射到整数(ID)?

c - C中的预处理器指令#pragma pack

c++ - 如何组合两个字符串?

c - 最后一封信开始

c - 如何并行运行定时器任务?

c++ - 使用预处理器将 JSON 作为字符串嵌入到 C++ 代码中

c++ - 指针容器模板设计

c++ - LLVM - 如何通过 MCJIT 正确使用全局变量

c++ - 为什么 cv::circle() 只显示在特定 RGB 值的 3D 矩阵上?