不带括号的C函数调用
C function call without bracket
这是一个简单的 C 程序:
#include <stdio.h>
int main(void)
{
printf("Display something\n");
fflush stdout;
return 0;
}
使用 msys2 mingw-w64 gcc 版本 7.3.0 和选项 -Wall 编译,一切正常,就好像第 5 行是 fflush(stdout);
。
我试图用我自己的函数重现这样的调用,但我得到了完全预期的错误
src/main.c: In function 'int main(int, char**)':
src/main.c:5:18: error: expected ';' before 'parameter'
custom_function parameter;
^~~~~~~~~
那么,fflush
函数会发生什么?有人可以解释一下吗?你和其他 C 编译器有相同的行为吗?
让我们看看预处理器输出(使用 MinGW 和 gcc -E test.c
命令行):
fflush
# 5 "test.c" 3
(&(* _imp___iob)[1])
# 5 "test.c"
;
如您所见,stdout
是一个宏,它扩展为带有括号的 (&(* _imp___iob)[1])
。
因此编译器使用这些括号并且语法没问题。
但这只是因为宏魔法,而且大多数宏都受括号保护以避免与其他标记(例如运算符优先级)产生副作用
您可以使用这个简单的代码在没有任何包含的情况下重现它:
#define arg ("hello")
void f(const char *x)
{
}
int main(int argc, char** argv)
{
f arg;
return 0;
}
当然这是不好的做法,会混淆 IDE(和人类),所以不要这样做。
您的问题:
请参阅让-弗朗索瓦·法布尔的回答。
里面的措辞有点奇怪
标准(而且我没有声称它不止于此)。
C99 7.19.1 说:
The header declares three types, several macros, and
many functions for performing input and output.
...
The macros are
...
stderr
stdin
stdout
which are expressions of type "pointer to FILE" that point to the
FILE objects associated, respectively, with the standard error,
input, and output streams.
正如 Keith Thompson 很久以前所说的那样
在上下文中,这表示它们是宏——但是所有的描述
其他宏使用短语 "which expands to"。对于标准错误,
stdin 和 stdout,它说它们 是 表达式(如果它们是
宏,严格来说是不正确的)。
如果允许它们是,比如说,声明的对象而不是宏,
那么应该更改 7.19.1p1 以允许这些声明,并且
stderr、stdin 和 stdout 的描述不应该是
页长 运行 上句。
更有可能的是,如果它们必须是宏,短语“which
是表达式”应该改为 "which expand to expressions".
不保证它们是宏。不过在你的情况下,
您很幸运,宏扩展为带有保护括号的表达式。
隐藏实际内容的邪恶宏的纯粹示例。
这是一个简单的 C 程序:
#include <stdio.h>
int main(void)
{
printf("Display something\n");
fflush stdout;
return 0;
}
使用 msys2 mingw-w64 gcc 版本 7.3.0 和选项 -Wall 编译,一切正常,就好像第 5 行是 fflush(stdout);
。
我试图用我自己的函数重现这样的调用,但我得到了完全预期的错误
src/main.c: In function 'int main(int, char**)':
src/main.c:5:18: error: expected ';' before 'parameter'
custom_function parameter;
^~~~~~~~~
那么,fflush
函数会发生什么?有人可以解释一下吗?你和其他 C 编译器有相同的行为吗?
让我们看看预处理器输出(使用 MinGW 和 gcc -E test.c
命令行):
fflush
# 5 "test.c" 3
(&(* _imp___iob)[1])
# 5 "test.c"
;
如您所见,stdout
是一个宏,它扩展为带有括号的 (&(* _imp___iob)[1])
。
因此编译器使用这些括号并且语法没问题。
但这只是因为宏魔法,而且大多数宏都受括号保护以避免与其他标记(例如运算符优先级)产生副作用
您可以使用这个简单的代码在没有任何包含的情况下重现它:
#define arg ("hello")
void f(const char *x)
{
}
int main(int argc, char** argv)
{
f arg;
return 0;
}
当然这是不好的做法,会混淆 IDE(和人类),所以不要这样做。
您的问题:
请参阅让-弗朗索瓦·法布尔的回答。 里面的措辞有点奇怪 标准(而且我没有声称它不止于此)。
C99 7.19.1 说:
The header declares three types, several macros, and many functions for performing input and output.
...
The macros are
...
stderr stdin stdout
which are expressions of type "pointer to FILE" that point to the FILE objects associated, respectively, with the standard error, input, and output streams.
正如 Keith Thompson 很久以前所说的那样 在上下文中,这表示它们是宏——但是所有的描述 其他宏使用短语 "which expands to"。对于标准错误, stdin 和 stdout,它说它们 是 表达式(如果它们是 宏,严格来说是不正确的)。
如果允许它们是,比如说,声明的对象而不是宏, 那么应该更改 7.19.1p1 以允许这些声明,并且 stderr、stdin 和 stdout 的描述不应该是 页长 运行 上句。
更有可能的是,如果它们必须是宏,短语“which 是表达式”应该改为 "which expand to expressions".
不保证它们是宏。不过在你的情况下, 您很幸运,宏扩展为带有保护括号的表达式。 隐藏实际内容的邪恶宏的纯粹示例。