它应该如何工作" #define stdin stdin"在/usr/include/stdio.h?

时间:2016-09-14 02:56:47

标签: c stdio

在/usr/include/stdio.h

/* C89/C99 say they're macros.  Make them happy.  */
#define stdin stdin
#define stdout stdout
#define stderr stderr

这应该如何运作?

5 个答案:

答案 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(以及stderrstdout)的宏,该宏将替换为全局变量stdin(以及stderr和{{ 1}}),如此严格地说,宏中的stdout s(和stdin s和stderr s)都不相同。