2017-07-28 136 views
1

我很難理解C預處理器在以下上下文中如何應用重寫規則。我有以下宏:C預處理器宏擴展

#define _A(x) "A" _##x 
#define _B(x) "B" _##x 
#define X(x) _##x 

的想法是,這些宏使用的連接來創建一個新的表達,其本身可以是一個宏觀 - 如果一個宏,我想這將擴大:現在

,下面的擴展,就像我期望:

X(x)  expands to _x 
X(A(x)) expands to "A" _x 
X(A(B(x))) expands to "A" "B" _x 

然而,一旦同宏多次使用,擴展停止:

X(A(A(x)))  expands to "A" _A(x), expected "A" "A" _x 
X(B(B(x)))  expands to "B" _B(x), expected "B" "B" _x 
X(A(B(A(x)))) expands to "A" "B" _A(x), expected "A" "B" "A" _x 
X(A(B(A(B(x))))) expands to "A" "B" _A(B(x)), expected "A" "B" "A" "B" _x 

我猜這裏有某種「只能擴展同名宏」的規則?我能做些什麼來讓宏按我想要的方式擴展嗎?

+1

這是因爲您使用'##'運算符,它不評估宏;這是[嵌套宏擴展](https://stackoverflow.com/questions/31610231/nested-macro-expansion) –

+1

或[如何評估嵌套的預處理器宏](https:// stackoverflow。com/questions/13074432/how-to-evaluate-an-nested-preprocessor-macro) –

+0

也許我的大腦工作不正常,但我不明白這些問題是如何重複的。在你關聯的問題中,問題是首先擴展宏,然後再連接。我想完全相反:先連接然後展開。另外,至少有一些擴展正在發生,或者我發佈的示例根本不會擴展(例如,我們會得到X(A(x)) - _A(x),但是_A(x)顯然會擴展) – MrMobster

回答

3

C99草案說,有沒有在宏展開允許遞歸:

6.10.3.4重新掃描和再替換

  1. 替換列表中的所有參數後已經取代和 ###處理已完成,所有地標標記預處理標記都將被刪除。然後重新掃描得到的預處理令牌序列 以及源文件的所有後續預處理令牌,以取代更多的宏名稱。
  2. 如果掃描 替換列表(不包括源文件的 預處理標記的其餘部分)的過程中發現被替換的宏 名,且未被替換。此外,如果任何 嵌套替換遇到正被替換的宏的名稱,則不會替換它 。這些未替換的宏名稱預處理 令牌不再可用於進一步替換,即使它們在其中宏名稱 預處理令牌本應已被替換的上下文中稍後(重新)檢查過時(重新)檢查。

所以X(A(A(x)))擴展到"A" _A(x),但擴張本身不是擴大,如您所見。

+0

Bah its its what what ... ... ... I I I I I I I I I I I I I I I I I I I I I I I I I I :) – MrMobster

+0

我不知道有什麼辦法來得到你想要的效果 - 對不起! –

+1

@MrMobster規避預處理器的最簡單方法是使用其他預處理器。看看M4處理器,例如http://mbreen.com/m4.html –

2

當我想要制定宏觀擴展時,我通常會使用這個圖,我使用標準的第6.10.3節構建這個圖。希望它可以幫助...

enter image description here

由於託比已經提到的,嵌套宏不會遞歸擴展。

+0

謝謝,這是非常有用的! – MrMobster

+0

......但錯了。在確定是否的路徑之後,塊表示「如果嵌套替換遇到宏的名稱被替換,它不會被替換以避免遞歸」。這是指藍色的油漆;但在重新掃描和進一步更換期間適用藍色塗料(6.10.3.4);並且該塊正在描述不帶有這種限制的參數替換(6.10.3.1)。 –

+0

糟糕。我必須檢查一下!在平均時間刪除答案 – Jimbo