2016-09-14 98 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)不一樣。