C函数调用无括号
这是一个简单的C程序:
#include 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
function会发生什么? 有人可以解释一下吗? 你和其他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(和人类),所以就是不要这样做。
你的问题:
参见Jean-FrançoisFabre的回答。 标准中的措辞有些奇怪(我并没有声称它不仅仅是那个)。
C99 7.19.1说:
标头声明了三种类型,几个宏,以及许多用于执行输入和输出的函数。
…
宏是
…
stderr stdin stdout
它是“指向FILE的指针”类型的表达式,它们分别指向与标准错误,输入和输出流相关联的FILE对象。
正如Keith Thompson早就说过的那样,在上下文中,这表示它们是宏 – 但是所有其他宏的描述都使用了“扩展为”的短语。 对于stderr,stdin和stdout,它表示它们是表达式(如果它们是宏,则不是严格正确的)。
如果允许它们是声明的对象而不是宏,那么应该更改7.19.1p1以允许这些声明,并且stderr,stdin和stdout的描述不应该是页面长度运行的一部分 – 一句话。
更合理的是,如果要求它们是宏,则应将“哪些是表达式”改为“扩展为表达式”。
它们不保证是宏。 在你的情况下,你很幸运宏扩展到带有保护括号的表达式。 隐藏实际内容的邪恶宏观的纯粹例子。