/usr/include/stdio.h 中的“#define stdin stdin”应该如何工作?

How is it supposed to work that "#define stdin stdin" in /usr/include/stdio.h?

在/usr/include/stdio.h

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

这应该如何运作?

宏被替换为它定义的值,因此每个宏都被完全替换为相同的值。只是将它们定义为宏,使它们成为“macros”,但它们被自己替换了,所以就像什么都不做,只是符合标准。

关键是宏一旦被展开,就不会在替换文本中再次被替换。这意味着当预处理器遇到 stderr 在:

fprintf(stderr, "Usage: %s file [...]\n", argv[0]);

它用 stderr 替换了 stderr 标记,然后重新扫描替换文本,但是 stderr 不再符合扩展条件,因此文本仍然是 stderr .

宏在其自身扩展后不会再次重新扩展,因此您不会以循环(和无限)宏扩展结束。

来自 ISO C99 标准的第 6.10.3.4/2 节:

If the name of the macro being replaced is found during this scan of the replacement list (not including the rest of the source file’s preprocessing tokens), it is not replaced. Furthermore, if any nested replacements encounter the name of the macro being replaced, it is not replaced. These nonreplaced macro name preprocessing tokens are no longer available for further replacement even if they are later (re)examined in contexts in which that macro name preprocessing token would otherwise have been replaced.

好问题。它确实用自己替换了一次。

但是在C11 6.10.3.4p2中有一条规则说宏名不再被替换

虽然其他人解释了预处理器的机制,但真正的原因是stdin等人。是全局变量,准确地说是文件指针。详情请参阅 GlibC-code

您的示例定义了一个名为 stdin(以及 stderrstdout)的宏,该宏将替换为全局变量 stdin(以及 stderrstdout),所以严格来说,宏中的 stdins(以及 stderrs 和 stdouts)是不一样的。