我的分号怎么了? (gcc 预处理器)

What happened to my semicolon? (gcc preprocessor)

我想我会很聪明,围绕 Disable/Enable 中断编写一个小的预处理器包装器,如下所示:

#define WITH_INTERRUPTS_DISABLED(_body)                                        \
  do {                                                                         \
    uint32_t primask = DisableGlobalIRQ();                                     \
    do {                                                                       \
      _body                                                                    \
    } while (0);                                                               \
    EnableGlobalIRQ(primask);                                                  \
  } while (0)

GCC 预处理器,与此源一起出现时:

WITH_INTERRUPTS_DISABLED(
  i += 2; 
  quux();
);

... 生成此输出(为了便于阅读而重新格式化):

do {
  uint32_t primask = DisableGlobalIRQ();
  do {
    i += 2;
    quux();
  } while (0);
  EnableGlobalIRQ(primask);
} while (0)

根据 Mr. Godbolt,所有 GCC 变体的行为都如上,省略了结束分号。同时,所有 clang 个变体的输出都包含分号。

有没有办法说服 GCC 包含分号?

分号没有任何问题,GCC 生成的很好。如果 GCC 和 clang 在这个基本的东西上有所不同,那将是非常令人吃惊的,这肯定是由 C 标准明确定义的,并且在实际代码中广泛使用。

但是Godbolt Compiler Explorer的默认设置会过滤掉它,可能是因为它看起来像汇编语言的注释。来自 interjay 的示例:https://godbolt.org/z/94e4q3ehK

如果您关闭“过滤器:评论”,您会看到分号在那里,前面有几个空行:https://godbolt.org/z/7n896or8Y

  do { uint32_t primask = DisableGlobalIRQ(); do { i += 2; quux(); } while (0); EnableGlobalIRQ(primask); } while (0)


   ;

正如 interjay 指出的那样,Explorer 旨在显示汇编输出,而不是预处理的 C,因此 -Enot supported very well 也就不足为奇了。

clang 似乎省略了空行,我猜这是为了防止 Godbolt 认为它是评论:

  do { uint32_t primask = DisableGlobalIRQ(); do { i += 2; quux(); } while (0); EnableGlobalIRQ(primask); } while (0);

我认为这种差异不存在任何合规性问题,因为两种情况下标记的顺序相同。