2014-09-03 189 views
0

我試圖通過宏的多層次逗號,但預處理器不喜歡......錯誤嘗試

// This is just simplified, in reality I have some other variadic function which will 
// stop upon encountering the -1 and APPEND_COMMA() may add more args (like `a, b,`) 

#include <stdio.h> 

#define MACRO_EX(val) printf("%d %d", val -1); 

#define MACRO(val) MACRO_EX(val) 

#define APPEND_COMMA(a) a, 

int main() { 
     MACRO(APPEND_COMMA(1)); 
     return 0; 
} 

到底是什麼導致編譯通過多個宏通逗號時在這裏失敗?

test.c:10:8: error: too many arguments provided to function-like macro invocation 
     MACRO(APPEND_COMMA(1)); 
      ^
test.c:7:26: note: expanded from macro 'APPEND_COMMA' 
#define APPEND_COMMA(a) a, 
         ^
test.c:5:29: note: expanded from macro 'MACRO' 
#define MACRO(val) MACRO_EX(val) 
          ^
test.c:3:9: note: macro 'MACRO_EX' defined here 
#define MACRO_EX(val) printf("%d %d", val 0); 
     ^
test.c:10:2: error: use of undeclared identifier 'MACRO_EX' 
     MACRO(APPEND_COMMA(1)); 
     ^
test.c:5:20: note: expanded from macro 'MACRO' 
#define MACRO(val) MACRO_EX(val) 
       ^
2 errors generated. 

逗號似乎在叫宏進行擴展,使MACRO_EX(a,)被調用,這不是我想要的。


我找到了一些辦法解決這個使用__VA_ARGS__

#define MACRO_EX(...) printf("%d %d", __VA_ARGS__ -1); 

但我真的喜歡乾淨地通過逗號通過所有宏到可變參數函數調用,並使用乾淨命名宏參數[就像我在我的原始代碼中打算的那樣]。

有什麼辦法可以達到這個目的嗎?

+0

在'gcc'編譯器中嘗試'-E'選項。 – 2014-09-03 14:20:28

+1

@ShafikYaghmour區別在於,逗號不是在宏調用中引入的,而是通過另一個宏引入的。這樣我可以將它傳遞給'MACRO()',但不知何故它會被擴展。 – bwoebi 2014-09-03 14:20:46

+0

@ Don'tYouWorryChild nope,這是一個預處理器故障,它停在那裏。如上所述,我知道發生了什麼,我想有一種方法可以像參數那樣傳遞它,而不是像__VA_ARGS __... – bwoebi 2014-09-03 14:22:04

回答

1

,以保證一個逗號將通過宏觀參數「乾淨地」傳遞的唯一方法是把它包在括號:

#define APPEND_COMMA(a) (a,) 

現在的APPEND_COMMA結果將永遠是一個預處理器的參數。

這個問題很明顯,它產生了printf("%d %d", (1,) -1);,它現在是有效的預處理器代碼,但不再有效的C代碼。這是通過插入一個「解壓」步驟進MACRO_EX定義修正:

#define IDENTITY(...) __VA_ARGS__ 
#define MACRO_EX(val) printf("%d %d", IDENTITY val -1); 

IDENTITY將解包的val的內容,假設val是parenthesised參數列表,在MACRO_EX的重新掃描步驟。

val可能因爲不包含逗號而不能加括號的情況怎麼辦?答案是不要讓它們出現。參數可能包含一個逗號應該總是被包裝,所以他們總是可以安全地解開在最後插入點。宏的設計需要知道他們是否期望單個令牌或列表*。這是預處理器的靜態類型約束的等價物:像MACRO這樣的宏需要一個類型爲list的參數,而不是類型atom(並且調用的宏類似地需要用正確的類型簽名書寫);在那些只需要單個參數的場合,將它們傳遞給單元素列表。

*在技術上可以設計一個宏來測試它的參數是否被括起來並在結果上分支,但是你在那裏進入黑暗魔法領域。爲了清晰起見,堅持固定類型。

+0

包裝和展開絕對是一個不錯的主意。謝謝你的提示。 – bwoebi 2014-09-03 22:55:06