2011-07-12 225 views
1

考慮以下代碼:延遲宏擴展

#define N_ 0 
#define N_X 1 
#define M(a) N_ 

M(arg)X; // #1 -- I'd like this to expand to N_X, and ultimately 1; but it's 0X instead 
M(arg);  // #2 -- this should and does expand to 0 

與#1的問題在於,擴展M()之後,結果包含N_,和與X相連來之前,預處理器發現和其擴展。 我可以以某種方式延遲對更多宏的結果重新掃描,以便預處理器找到N_X而不是N_?

回答

7

首先在N_ XN_X之間有所不同。第一個是兩個令牌。爲了形成一個令牌,你必須使用標記粘貼操作##,但該運營商抑制宏擴展,所以這樣的:

M(a) ## X //Compiler error can't paste ')' and X 

導致編譯錯誤,因爲它試圖粘貼M(a)而不是N_。您可以允許宏通過使用宏一層額外的粘貼之前擴大(這實在是常用宏):

#define PRIMITIVE_CAT(x, y) x ## y 
#define CAT(x, y) PRIMITIVE_CAT(x, y) 

然而,在你的情況下,這仍然無法工作:

CAT(M(a), X) //expands to 0 

這是因爲您正在使用對象宏而不是函數宏。如果您將其更改爲功能宏,它會工作,你怎麼想:

#define N_() 0 
#define N_X() 1 
#define M(a) N_ 

CAT(M(arg), X)() // expands to 1 
M(arg)()  // expands to 0 

功能宏功能更強大,可以延遲他們的擴張。這裏是你如何能延緩他們一個掃描:

#define EMPTY() 
#define DEFER(x) x EMPTY() 

N_() //Expands to 0 
DEFER(N_)() //Expands N_() 

延遲宏展開這樣的是遞歸可在預處理器實現的途徑之一。

2

否。預處理器一行一行地工作,不執行任何遞歸或回溯。它讀取一行,處理特殊的#行或替換某些內容,然後轉到下一行。這也意味着它不會在#define之前或#undef之後進行任何替換。你必須解決這個問題。

+0

和宏一般都是邪惡的 – Drakosha

+2

Drakosha:我會不同意。瞭解他們和他們的陷阱,他們可以成爲一個方便的工具。 – orlp

+0

nightcracker:當然,你需要學習它們,但你應該儘量避免使用它們,除非它是最後一個選項(並且我upvoted你的答案) – Drakosha