2011-05-05 89 views
13

我在通話宏觀工作,複雜的宏零個參數

#define CALL(f,...) FN(f)->call((ref(new LinkedList()), __VA_ARGS__)) 

,要求時,

CALL(print,2,3,4,5); 

增加2 3 4 5到鏈​​表(,超載這樣做),並呼籲打印預計鏈接列表,如預期般運作如何有一些不需要參數的呼叫,

CALL(HeapSize); 

它仍然需要一個鏈接列表,但一個空的,以上不起作用,我試圖想出一個宏,可以與任何一種風格工作?

編輯:挖通過量gcc的文檔,我發現,加入##之前VA_ARGS刪除,當沒有爭論,但與我不能嵌套宏,

CALL(print,CALL(HeadSize)); 

這將導致CALL沒有定義的錯誤如何,如果我分開它的工作電話

+1

根據傳遞參數的數量,您可以將'CALL'委託給不同的宏。我演示瞭如何做到這一點[在另一個問題的答案](http://stackoverflow.com/questions/5355241/generating-function-declaration-using-a-macro-iteration/5355946#5355946)。這不需要任何實現特定的黑客。 – 2011-05-05 00:30:40

+0

也見http://stackoverflow.com/questions/5588855/standard-alternative-to-gccs-va-args-trick – 2012-02-09 03:26:21

回答

14

至於更新的問題,通過使用輔助宏VA_ARGS如 以下,參數將按預期展開。

#define VA_ARGS(...) , ##__VA_ARGS__ 
#define CALL(f,...) FN(f)->call((ref(new LinkedList()) VA_ARGS(__VA_ARGS__))) 
+0

P.S.這對我的情況很好,我需要在最後加NULL: #define blah(x,...)actual(a,b,c,## _VA_ARGS __,NULL) – Brad 2012-10-23 19:15:56

+1

我一直在使用這個技巧直到我發現在編譯C99甚至C11時在gcc的迂迴模式下,這會產生一個警告。那麼,不完全是這個宏定義本身,而是調用一個零變量部分的可變宏。爲什麼,哦,他們爲什麼不允許它在C11標準?! – 2017-02-16 10:52:58

0

不幸的是,這不能做到。您將需要定義一個單獨的宏來完成此調用。

如你結束了無效的參數時VA_ARGS與什麼你具有浮動,

#define CALL0(f) FN(f)->call((ref(new LinkedList()))) 
4

最終如果使用GCC取代的,它有一個延伸吞掉之前的逗號__VA_ARGS__。請參閱:http://gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.html

+0

只因爲你更徹底。 :) – 2011-05-05 00:28:29

+0

即使沒有在他們的MSDN頁面上提及,MSVC也支持相同的擴展,讓每個人的生活都變得更加輕鬆。 – vanza 2011-05-05 00:28:50

+3

@vanza:實際上,MSVC會自動爲你「自動」執行它 - 如果你有一個序列',__VA_ARGS__'在宏中,'__VA_ARGS__'是空的,它會自動吞下(刪除)','。如果兩個標記之間不能合併,它也會忽略'##',所以gcc擴展工作在serendipity。 – 2014-04-18 16:26:43

3

如果你正在使用gcc/G ++還有一個辦法:

#define CALL(f,...) FN(f)->call((ref(new LinkedList()), ## __VA_ARGS__)) 

fine manual

[...]如果可變參數被忽略或爲空,` ##'運算符會導致預處理器在其之前刪除逗號。

因此,gcc專門爲您面臨的問題擴展/黑客。

+1

我編輯了這個問題,我在文檔中發現了相同的東西,但是它不能嵌套宏。 – 2011-05-05 00:30:14

0

只需將f作爲...的一部分,然後使用單獨的宏提取您需要的第一個參數f

1

這些答案中的一個常見主題是我們需要一個GCC特定的黑客攻擊。一種方法是使用令牌粘貼##__VAR_ARGS__,但粘貼的參數不是宏擴展的,這意味着宏不能嵌套。但是,如果你打算做一些具體的事情GCC無論如何,那麼爲什麼不使用老式的GCC擴展:

#define VARARG_FOO(ZeroOrMoreArgs...) \ 
    printf("VARARG_FOO: " ZeroOrMoreArgs) 

ZeroOrMoreArgs簡單地由所有參數(如果有的話),逗號和全部換掉。這包括遞歸宏擴展。

  • 然後VARARG_FOO()擴展到printf("VARARG_FOO: ")
  • VARARG_FOO("I iz %d", 42)擴展到printf("VARARGFOO: " "I iz %d", 42)

最後

#define NEST_ME "I tawt I taw a puddy tat" 
VARARG_FOO("The evil one says %s", NEST_ME); 

將擴大到

printf("VARARG_FOO: " "The evil one says %s", "I tawt I taw a puddy tat"); 

優點:

  • 您可以嵌套宏調用,同時具有零以上aguments。

缺點:

  • ##__VA_ARGS__破解可能是在案件標準的C程序,他們總是至少有一個逗號無害。 (我沒有想過這是否是真的)。
  • 根據@ScootMoonen ##__VA_ARGS__黑客是MSVC的無證延伸。