2016-09-14 101 views

回答

5

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

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

它取代了stderr令牌stderr,然后重新扫描替换文本,但stderr不再有资格进行扩展,所以文本保持stderr

2

宏被定义的值以文本方式替换,所以每个宏都被相同的值替换。只是将它们定义为宏,使它们成为“宏”“,但它们被自己替换,所以它就像什么也不做,只是符合标准。

4

一个宏在自己的扩展之后不会再次扩展,所以你不会以循环(和无限)的宏扩展结束。

从ISO C99标准的部分6.10.3.4/2:

如果宏被替换该扫描替换列表中(不包括源文件的预处理的休息期间发现的名称令牌),它不会被替换。此外,如果任何嵌套替换遇到被替换的宏的名称,则不会被替换。这些未替换的宏名预处理令牌不再用于进一步的替换,即使它们在其中宏名预处理令牌本来会被替换的上下文中的后续(重新)检查中也是如此。

0

好问题。它确实取代了一次。

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

0

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

您的示例宏定义了一个名为stdin(和stderrstdout)与全局变量stdin(和stderrstdout)来代替宏观,所以严格来说,两者stdin S(和stderr S和stdout S)不一样。