为什么 "do ... while (0)" 不能用简单的大括号代替?
Why "do ... while (0)" can't be replaced by simple curly brackets?
最近看到一段C代码,里面有一个宏,格式如下:
#define TOTO() \
do { \
do_something(); \
do_another_something(); \
} while (0)
起初我想知道这里 do while (0)
的目的,但是 this answer 向我解释说:这是为了防止在 if
或 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
,所以我只用大括号测试了相同的代码。我的整个代码如下所示:
#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;
}
但是 GCC 给我以下错误:
error: ‘else’ without a previous ‘if’
但是main
函数的代码应该展开为:
if (argc == 1)
{
printf("hello ");
printf("world!\n");
}
else
fprintf(stderr, "nope\n");
return 0;
哪个有效。
那么我在这里错过了什么?
宏后面的分号
宏扩展为:
if (argc == 1)
{
printf("hello "); \
printf("world!\n"); \
};
else // HERE, SYNTAX ERROR
fprintf(stderr, "nope\n");
return 0;
由于 if
语句的主体和 else
子句之间不应有分号,因此这是一个语法错误。
OTOH,do
-while
循环允许(并且需要)一个分号。
只需打印真实的预处理器输出即可轻松避免对编译器输出的误解。这可以通过使用
gcc
可执行文件的 -E
开关。来自 man 1 gcc
:
-E Stop after the preprocessing stage; do not run the compiler
proper. The output is in the form of preprocessed source code,
which is sent to the standard output.
- 直接以
cpp
可执行文件形式的预处理器。
感谢
- @dhke 用于更正发生错误的行。
- @kakeh 建议事先查看预处理器输出。
仔细查看您调用宏的方式。
你必须写
if (argc == 1)
HELLO_WORLD() // NO SEMICOLON!!!!!!!
else
fprintf(stderr, "nope\n");
这太可怕了,因为您永远无法用真正的函数替换 HELLO_WORLD 宏。
最近看到一段C代码,里面有一个宏,格式如下:
#define TOTO() \
do { \
do_something(); \
do_another_something(); \
} while (0)
起初我想知道这里 do while (0)
的目的,但是 this answer 向我解释说:这是为了防止在 if
或 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
,所以我只用大括号测试了相同的代码。我的整个代码如下所示:
#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;
}
但是 GCC 给我以下错误:
error: ‘else’ without a previous ‘if’
但是main
函数的代码应该展开为:
if (argc == 1)
{
printf("hello ");
printf("world!\n");
}
else
fprintf(stderr, "nope\n");
return 0;
哪个有效。
那么我在这里错过了什么?
宏后面的分号
宏扩展为:
if (argc == 1)
{
printf("hello "); \
printf("world!\n"); \
};
else // HERE, SYNTAX ERROR
fprintf(stderr, "nope\n");
return 0;
由于 if
语句的主体和 else
子句之间不应有分号,因此这是一个语法错误。
OTOH,do
-while
循环允许(并且需要)一个分号。
只需打印真实的预处理器输出即可轻松避免对编译器输出的误解。这可以通过使用
gcc
可执行文件的-E
开关。来自man 1 gcc
:
-E Stop after the preprocessing stage; do not run the compiler proper. The output is in the form of preprocessed source code, which is sent to the standard output.
- 直接以
cpp
可执行文件形式的预处理器。
感谢
- @dhke 用于更正发生错误的行。
- @kakeh 建议事先查看预处理器输出。
仔细查看您调用宏的方式。
你必须写
if (argc == 1)
HELLO_WORLD() // NO SEMICOLON!!!!!!!
else
fprintf(stderr, "nope\n");
这太可怕了,因为您永远无法用真正的函数替换 HELLO_WORLD 宏。