在/usr/include/stdio.h它应该如何在/usr/include/stdio.h中使用“#define stdin stdin”?
/* C89/C99 say they're macros. Make them happy. */
#define stdin stdin
#define stdout stdout
#define stderr stderr
这是怎么应该工作?
在/usr/include/stdio.h它应该如何在/usr/include/stdio.h中使用“#define stdin stdin”?
/* C89/C99 say they're macros. Make them happy. */
#define stdin stdin
#define stdout stdout
#define stderr stderr
这是怎么应该工作?
关键在于一旦宏被扩展了,它就不会在替换文本中再次被替换。这意味着,当预处理器遇到stderr
在:
fprintf(stderr, "Usage: %s file [...]\n", argv[0]);
它取代了stderr
令牌stderr
,然后重新扫描替换文本,但stderr
不再有资格进行扩展,所以文本保持stderr
。
宏被定义的值以文本方式替换,所以每个宏都被相同的值替换。只是将它们定义为宏,使它们成为“宏”“,但它们被自己替换,所以它就像什么也不做,只是符合标准。
一个宏在自己的扩展之后不会再次扩展,所以你不会以循环(和无限)的宏扩展结束。
从ISO C99标准的部分6.10.3.4/2:
如果宏被替换该扫描替换列表中(不包括源文件的预处理的休息期间发现的名称令牌),它不会被替换。此外,如果任何嵌套替换遇到被替换的宏的名称,则不会被替换。这些未替换的宏名预处理令牌不再用于进一步的替换,即使它们在其中宏名预处理令牌本来会被替换的上下文中的后续(重新)检查中也是如此。
好问题。它确实取代了一次。
但是,在C11 6.10.3.4p2中有一条规则说宏名不会再被替换。
虽然其他人解释了预处理器的机制,但其实际原因是stdin
et al。是全局变量,准确的文件指针。详情请参阅GlibC-code。
您的示例宏定义了一个名为stdin
(和stderr
和stdout
)与全局变量stdin
(和stderr
和stdout
)来代替宏观,所以严格来说,两者stdin
S(和stderr
S和stdout
S)不一样。
阅读上面的评论。 –
@iharob该评论解释了*为什么他们被定义;它没有解释*宏如何工作。 – jamesdlin
@jamesdlin尽管有6个评论,但你完全正确。 –