在/usr/include/stdio.h
/* C89/C99 say they're macros. Make them happy. */
#define stdin stdin
#define stdout stdout
#define stderr stderr
这应该如何运作?
答案 0 :(得分:5)
关键是,一旦扩展了宏,它就不会在替换文本中再次替换。这意味着当预处理器遇到stderr
时
在:
fprintf(stderr, "Usage: %s file [...]\n", argv[0]);
它会将stderr
令牌替换为stderr
,然后重新扫描替换文字,但stderr
不再符合扩展条件,因此文字仍为stderr
。< / p>
答案 1 :(得分:4)
宏在自身扩展后不会再次重新展开,因此您不会以循环(和无限)宏扩展结束。
从ISO C99标准的第6.10.3.4/2节开始:
如果在替换列表的扫描期间(不包括源文件的其余预处理标记)找到要替换的宏的名称,则不会替换它。此外,如果任何嵌套替换遇到要替换的宏的名称,则不会替换它。这些无法替换的宏名称预处理令牌不再可用于进一步替换,即使它们稍后(重新)检查在上下文中 否则,宏名称预处理令牌将被替换。
答案 2 :(得分:2)
宏被文本替换为其定义的值,因此每个宏都被相同的值替换。只是将它们定义为宏来使它们成为“宏”,但它们会被它们自己取代,所以它就像什么也不做,只是符合标准。
答案 3 :(得分:0)
好问题。它确实一次取代它自己。
但是,在C11 6.10.3.4p2中,有一条规则说宏名称不会再被替换。
答案 4 :(得分:0)
虽然其他人解释了预处理器的机制,但实际的原因是stdin
等。是全局变量,准确的文件指针。有关详细信息,请参阅GlibC-code。
您的示例定义了一个名为stdin
(以及stderr
和stdout
)的宏,该宏将替换为全局变量stdin
(以及stderr
和{{ 1}}),如此严格地说,宏中的stdout
s(和stdin
s和stderr
s)都不相同。