2013-12-08 68 views
0

如果我有:#define in #define;預處理器中發生了什麼?

#define X 5 
#define Y X 

在預處理會發生什麼爲樣的事情? 它是否經歷整個文件並將每個X更改爲5, 然後回到下一個定義,然後將每個Y更改爲5(因爲在前一次迭代中Y得到5)?

+0

你試過了嗎?它不應該超過半分鐘。發生了什麼? – Jon

+1

用gcc -E編譯你的代碼,你可以看到預處理器產生了什麼樣的代碼 – MOHAMED

回答

4

C標準有一個關於宏如何擴展的特殊術語。

宏名實際上存儲在「此時定義的所有宏」的大表中。左側的每個表格條目「宏名稱」(以及中間的任何參數)和右側的「擴展令牌流」。

當宏要被擴展(因爲它發生在一些非預處理線中,或者在一個預處理線,其中它必須擴大的位置 - 例如,可以#define STDIO <stdio.h>然後​​),表條目是「塗成藍色」,然後讀取替換的標記流(參數擴展也由標準規定)。

如果更換令牌流包含原始宏的名稱,它不再匹配,因爲「藍漆」掩蓋了名。

當更換令牌流已經完全處理,「藍漆」被刪除,重新露出了名。

因此:

#define X 5 

增加X:(無參數),5到表中。

然後:

#define Y X 

補充說:Y:(無參數),X表。

文件中的某個地方之後,你可能有令牌Y的發生。假定既沒有上述已#undef ED(從表中刪除),編譯器必須首先「塗料的Y藍色表項」,並與令牌X替換令牌Y

接下來,編譯器必須「繪製X藍色的表格條目」,並用標記5替換標記X

令牌5不是預處理器宏名稱(它不能被定義),因此令牌5超出了預處理階段的範圍。現在,從「X」表格條目中刪除「藍色油漆」,就像這樣;然後從Y條目中刪除「藍色油漆」,這也完成了。


如果你是不是寫:

#define Y Y, Y, Y, the letter is called Y! 

那麼序列,在遇到後面的標記Y,應該是:

  1. 油漆條目Y藍色
  2. 下降替換令牌序列:Y,Y,Y,theletteriscalledY!
  3. 檢查表中的每個替換標記 - 因爲Y被塗成藍色的那些不匹配,並且,無法比擬的,所以這些都轉嫁到編譯器的休息; the,letter,iscalled必須檢查,但可能不在表中,因此傳遞; Y仍然被塗成藍色,因此不匹配並被傳遞,並且!無法匹配並被傳遞。
  4. 刪除藍色塗料,恢復擴展