在/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個評論,但你完全正確。 –