2014-01-31 30 views
5

如何可以在一個限定一個C宏IFARGS(YES, NO, ...)使得調用IFARGS,沒有額外的參數產生NO,並與一個或多個參數產生YES調用IFARGS檢測在存在或不存在的參數爲C宏

我有一個使用GCC的答案(見下文),但如果可能的話(或證明它是不可能的),我更願意使用C99。

回答

1
#define GET(_0, _1) _0 // Return the first of two arguments 
#define GET_(_0, _1) _1 // Return the second of two arguments 

#define JOIN(_0, _1) _0 ## _1 // Concatenate two arguments 
#define EJOIN(_0, _1) JOIN(_0, _1) // Expand macros and concatenate 

#define FIRST(_, ...) _ // Truncate everything after first comma 
#define EFIRST(_) FIRST(_) // Expand argument and pass to FIRST 

#define REST(_0, ...) __VA_ARGS__ // Remove everything before first comma 

#define GET_GET(...) \ 
    EJOIN(GET, EFIRST(REST(,,##__VA_ARGS__ _))) // Branch between GET and GET_ 

#define IFARGS(YES, NO, ...) GET_GET(__VA_ARGS__)(YES, NO) 

需要注意的是,如果這在C99是可能的,那麼這將是可以模擬##__VA_ARGS__,就像這樣:

#define PREPEND_COMMA(...) , __VA_ARGS__ 
#define NO_COMMA() 
#define PREPEND_COMMA_IF_NONEMPTY(...) IFARGS(PREPEND_COMMA, NO_COMMA, __VA_ARGS__)(__VA_ARGS__) 

隨後的, ##__VA_ARGS__任何情況下,可以通過PREPEND_COMMA_IF_NONEMPTY(__VA_ARGS__)取代。

+0

這不是一個真正的答案,而僅僅是對自己問題的補充。 –

+0

@JensGustedt第一個代碼框是一個部分解決方案 - 它具有所需的行爲,但需要'## __ VA_ARGS__',這是C99宏語法的GCC擴展。 – augurar

+0

我注意到了。關於SO的一些研究可能已經向你揭示了一個答案。請參閱上面的鏈接。 –

4

在C99中,可以檢測宏參數是否爲空,但是對於可能出現在該參數中的所有可能性(自身擴展的參數,包含()以及類似的東西)很難實現。我的宏包P99實現了這樣的事情,所以你不必擔心太多。由於您的宏可以實現爲

#define IFARGS(YES, NO, ...) P99_IF_EMPTY(__VA_ARGS__)(YES(__VA__ARGS__))(NO()) 

正如其名稱所示,P99僅建立在C99功能上。

+0

如何檢測C99中的空參數? – augurar

+0

@augurar,這是在我最喜歡的搜索引擎的頂級搜索:) http://gustedt.wordpress.com/2010/06/08/detect-empty-macro-arguments/ –

+0

有趣的;然而,該文章中的「ISEMPTY」宏在給出16個參數時似乎失敗。 – augurar