为什么"做...而(0)"不能用简单的花括号代替?

时间:2016-01-15 09:15:38

标签: c scope macros curly-braces

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

#define TOTO()              \
do {                        \
  do_something();           \
  do_another_something();   \
} while (0)

我起初想知道do while (0)在这里的目的,但是this answer向我解释:如果宏只是在if或{{1}后使用的话没有大括号,像这样:

else

所以在这里,如果没有if (something) TOTO(); else do_something_else(); 语句,代码将扩展为:

do while (0)

哪种语法错误,因为if (something) do_something(); do_another_something(); else do_something_else(); 不再直接跟随else范围。

但是我认为它可以通过在自己的范围内声明宏而没有必要的if,所以我用大括号测试了相同的代码。我的整个代码如下所示:

do while

但是GCC给了我以下错误:

  

错误:'else'没有先前的'if'

但是,#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; } 函数的代码应扩展为:

main

哪个有效。

那我在这里错过了什么?

2 个答案:

答案 0 :(得分:9)

宏观之后的分号。

将宏扩展为此:

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

由于if - 语句的正文和else - 子句之间不应有分号,因此语法错误。
OTOH,do - while循环允许(并且需要)分号。

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

来实现
  • -E可执行文件的gcc开关。来自man 1 gcc
  

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

  • 预处理器直接形状为cpp可执行文件。

谢谢
- @dhke用于纠正错误发生的行。
- @kakeh提供预先查看预处理器输出的建议。

答案 1 :(得分:2)

仔细查看您如何调用宏。

你必须写

if (argc == 1)
    HELLO_WORLD() // NO SEMICOLON!!!!!!!
else
    fprintf(stderr, "nope\n");

这将是一种神经质,因为你永远不能用真实函数替换HELLO_WORLD宏。