2009-10-20 42 views
88

我想創建一個C宏,該行創建一個名稱爲 的函數。 我想我可以做這樣的事情(真正的功能將有大括號內的語句):使用##和__LINE__創建C宏(與定位宏連接的令牌)

#define UNIQUE static void Unique_##__LINE__(void) {} 

這一點我希望這將擴大到是這樣的:

static void Unique_23(void) {} 

這是行不通的。與令牌串接,定位宏 字面上處理,結束了擴大到:

static void Unique___LINE__(void) {} 

這是可能的嗎?

(是的,有一個真正的原因,我想這樣做,不管這看起來多麼無用)。

+2

可能重複的[如何連接使用C預處理器兩次,然後展開一個宏,如「arg ## \ _ ## MACRO」?](http://stackoverflow.com/questions/1489932/how-to-concatenate-twice-with-the-c- preprocessor- and-expand-a-macro-as-in-arg)除了'__LINE__'之外,任何宏都是一樣的(儘管這是一個常見的用例。 – 2015-06-21 09:54:51

+0

我認爲你可以通過[間接宏擴展](http://en.wikipedia.org/wiki/C_preprocessor#Indirectly_quoting_macro_arguments)來獲得此功能。 – 2009-10-20 20:28:32

回答

151

問題是,如果您有宏替換,則預處理器將只會遞歸地擴展宏,如果字符串化運算符#和令牌粘貼運算符##都未應用於它。的UNIQUE膨脹時

#define TOKENPASTE(x, y) x ## y 
#define TOKENPASTE2(x, y) TOKENPASTE(x, y) 
#define UNIQUE static void TOKENPASTE2(Unique_, __LINE__)(void) {} 

然後,__LINE__被擴展到行號(因爲它是:所以,你必須使用間接的一些額外的圖層,可以使用標記粘貼運算符和遞歸擴展的參數不涉及###),然後令牌粘貼發生在TOKENPASTE的擴展期間。

還應該注意的是,還有__COUNTER__宏,如果您需要在同一行上有多個UNIQUE宏的實例,則該宏在每次評估時會擴展爲新的整數。注意:MS Visual Studio,GCC(自V4.3)和Clang支持__COUNTER__,但不是標準C.

+2

恐怕這不適用於GNU cpp。 TOKENPASTE使用__LINE__作爲文字。 TOKENPASTE(Unique_,__LINE__)擴展爲Unique___LINE__ – 2009-10-20 20:58:16

+2

@DD:D'oh,現在已修復。它需要2層間接,而不是1. – 2009-10-20 21:04:15

+0

'__COUNTER__'宏在gcc中不適用於我;儘管'__LINE__'的確按照廣告的方式工作。 – Tyler 2011-09-30 00:27:44

-2

GCC不需要「包裝」(或實現),除非結果需要「字符串化」。海灣合作委員會有功能,但所有可以用簡單的C版本1(和一些認爲伯克利4.3 C是如此之快,這是值得學習如何使用)。 012(ll ll ll ll cla cla cla cla cla cla cla cla cla cla cla cla cla cla cla cla cla cla cla cla cla cla#########################或*作爲C預處理器的宏擴展預計將持續數十年。主要的例子是編譯X11,宏「Concat3」壞了,結果現在是MISNAMED C標識符,這當然不能構建。我開始建造失敗是他們的職業。

我想這裏的答案是「打破標準的新C是壞的C」,這些黑客總是選擇(clobber命名空間),他們無緣無故地改變默認值,但並不真正「改善C」(除了他們自己的說法所以:我說的是用來解釋爲什麼他們逃脫了所有的破壞,沒有人讓他們負責)。


這並不是說早期的前C處理器不支持UNIq_()__,因爲他們支持的#pragma允許「在代碼編譯品牌兩輪牛車被標記爲兩輪牛車」,也只是功能相關的問題以及沒有影響標準:就像改變默認值是無用的餛飩破壞一樣,同樣使用相同名稱(命名空間破壞)改變函數的功能是...在我看來惡意軟件