为什么"do ... while(0)"不能被简单的花括号替换?

Ara*_*hor 1 c macros scope curly-braces

我最近看到一段C代码,包括以下样式的宏:

#define TOTO()              \
do {                        \
  do_something();           \
  do_another_something();   \
} while (0)
Run Code Online (Sandbox Code Playgroud)

我起初想知道do while (0)这里的目的,但是这个答案向我解释:如果宏只是在一个ifelse没有花括号之后使用,就像这样:

if (something)
    TOTO();
else
    do_something_else();
Run Code Online (Sandbox Code Playgroud)

所以这里没有do while (0)语句,代码将扩展为:

if (something)
    do_something();
    do_another_something();
else
    do_something_else();
Run Code Online (Sandbox Code Playgroud)

这在语法上是错误的,因为else它不再直接跟随if范围.

但是我认为它可以通过在自己的范围内声明宏来实现,而不必do while围绕它,所以我用大括号测试了相同的代码.我的整个代码如下所示:

#include <stdio.h>

#define HELLO_WORLD()       \
{                           \
    printf("hello ");       \
    printf("world!\n");     \
}

int     main(int argc, char** argv)
{
    if (argc == 1)
        HELLO_WORLD();
    else
        fprintf(stderr, "nope\n");
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

但是GCC给了我以下错误:

错误:'else'没有前一个'if'

但是,该main函数的代码应扩展为:

if (argc == 1)
    {
        printf("hello ");
        printf("world!\n");
    }
else
    fprintf(stderr, "nope\n");
return 0;
Run Code Online (Sandbox Code Playgroud)

这是有效的.

那我在这里错过了什么?

cad*_*luk 9

它是宏之后的分号.

宏被扩展为此:

if (argc == 1)
    {
        printf("hello ");       \
        printf("world!\n");     \
    };
else        // HERE, SYNTAX ERROR
    fprintf(stderr, "nope\n");
return 0;
Run Code Online (Sandbox Code Playgroud)

由于if-statement 的主体和-clause 之间不应该有分号else,因此这是一个语法错误.
OTOH,a do- while循环允许(并且需要)分号.


只需打印真实的预处理器输出,就可以轻松避免对编译器输出的误解.这可以通过使用

  • 可执行文件的-E切换gcc.来自man 1 gcc:

-E在预处理阶段后停止; 不要正确运行编译器.输出采用预处理源代码的形式,发送到标准输出.

  • 预处理器直接在cpp可执行文件的形状.

感谢
- @dhke纠正错误发生在.
- @kakeh提供预先查看预处理器输出的建议.