2011-09-24 45 views
7

是否可以定義宏的宏內容?從宏的內容中定義一個宏

例如:

#define SET(key,value) #define key value 

SET(myKey,"value") 

int main(){ 
    char str[] = myKey; 
    printf("%s",str); 
} 

將導致

int main(){ 
    char str[] = "value"; 
    printf("%s",str); 
} 

被預處理之後。

爲什麼要這樣做?因爲我很好奇;)

+0

編輯您的片段所以它有編制的機會;並嘗試編譯它。怎麼了?我也很好奇。 –

+2

@PeteWilson試圖編譯上面的代碼,我得到錯誤:'#'後面沒有宏參數,因爲錯誤 – Linsey

+0

+1「爲什麼我會這樣做?」 :-) –

回答

5

不,它不可能在另一個宏中定義一個宏。

2

預處理器只在編譯器之前迭代一次。你的建議將需要不確定的迭代次數。

+0

預處理器不會簡單地確定宏。預處理器允許您多次使用#undef和#define宏。它在整個處理過程中更改和編輯宏,沒有任何東西會阻止它在宏內編輯這些規則。 – Linsey

+0

預處理程序的功能是「按照某種順序遍歷所有文件並替換某些字符串」。有一個命令的事實允許它有內存和#undef #ifdef等等......但是,要將被替換的字符串作爲宏需要遞歸。 – Willy

+0

請你舉個例子。如果你想替換內部'#define'前面的文本,我同意遞歸將是必需的,但是如果代碼從點開始生效似乎沒有問題。 – Linsey

0

宏是一個簡單的文本替換。從宏生成新的預處理器指令需要預處理器繼續從替換的開始進行預處理。但是,標準定義的預處理繼續後面的的替換。

從流動的角度來看,將未處理的代碼視爲輸入流,並將處理後的代碼視爲輸出流。宏替換可以具有任意長度,這意味着從一開始就預處理時必須在輸入流的開始處插入任意數量的字符以再次處理。

當處理繼續進行替換時,輸入簡單地在一次單獨運行中處理,沒有任何插入或緩衝,因爲所有內容都直接進入輸出。

0

雖然不可能使用宏來定義另一個宏,但取決於您要實現的內容,可以使用宏來定義常量來有效地實現相同的功能。例如,我有一個用來定義客觀C常量字符串和鍵值的廣泛C庫宏庫。

這裏是我的一些標題的一些代碼片段。

// use defineStringsIn_X_File to define a NSString constant to a literal value. 
// usage (direct) : defineStringsIn_X_File(constname,value); 

#define defineStringsIn_h_File(constname,value) extern NSString * const constname; 
#define defineStringsIn_m_File(constname,value) NSString * const constname = value; 


// use defineKeysIn_X_File when the value is the same as the key. 
// eg myKeyname has the value @"myKeyname" 
// usage (direct) : defineKeysIn_X_File(keyname); 
// usage (indirect) : myKeyDefiner(defineKeysIn_X_File); 
#define defineKeysIn_h_File(key) defineStringsIn_h_File(key,key) 
#define defineKeysIn_m_File(key) defineStringsIn_m_File(key,@#key) 



// use defineKeyValuesIn_X_File when the value is completely unrelated to the key - ie you supply a quoted value. 
// eg myKeyname has the value @"keyvalue" 
// usage: defineKeyValuesIn_X_File(keyname,@"keyvalue"); 
// usage (indirect) : myKeyDefiner(defineKeyValuesIn_X_File); 
#define defineKeyValuesIn_h_File(key,value) defineStringsIn_h_File(key,value) 
#define defineKeyValuesIn_m_File(key,value) defineStringsIn_m_File(key,value) 



// use definePrefixedKeys_in_X_File when the last part of the keyname is the same as the value. 
// eg myPrefixed_keyname has the value @"keyname" 
// usage (direct) : definePrefixedKeys_in_X_File(prefix_,keyname); 
// usage (indirect) : myKeyDefiner(definePrefixedKeys_in_X_File); 

#define definePrefixedKeys_in_h_File_2(prefix,key) defineKeyValuesIn_h_File(prefix##key,@#key) 
#define definePrefixedKeys_in_m_File_2(prefix,key) defineKeyValuesIn_m_File(prefix##key,@#key) 

#define definePrefixedKeys_in_h_File_3(prefix,key,NSObject) definePrefixedKeys_in_h_File_2(prefix,key) 
#define definePrefixedKeys_in_m_File_3(prefix,key,NSObject) definePrefixedKeys_in_m_File_2(prefix,key) 

#define definePrefixedKeys_in_h_File(...) VARARG(definePrefixedKeys_in_h_File_, __VA_ARGS__) 
#define definePrefixedKeys_in_m_File(...) VARARG(definePrefixedKeys_in_m_File_, __VA_ARGS__) 




// use definePrefixedKeyValues_in_X_File when the value has no relation to the keyname, but the keyname has a common prefixe 
// eg myPrefixed_keyname has the value @"bollocks" 
// usage: definePrefixedKeyValues_in_X_File(prefix_,keyname,@"bollocks"); 
// usage (indirect) : myKeyDefiner(definePrefixedKeyValues_in_X_File); 
#define definePrefixedKeyValues_in_h_File(prefix,key,value) defineKeyValuesIn_h_File(prefix##key,value) 
#define definePrefixedKeyValues_in_m_File(prefix,key,value) defineKeyValuesIn_m_File(prefix##key,value) 







#define VA_NARGS_IMPL(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, N, ...) N 
#define VA_NARGS(...) VA_NARGS_IMPL(X,##__VA_ARGS__, 11, 10,9, 8, 7, 6, 5, 4, 3, 2, 1, 0) 
#define VARARG_IMPL2(base, count, ...) base##count(__VA_ARGS__) 
#define VARARG_IMPL(base, count, ...) VARARG_IMPL2(base, count, __VA_ARGS__) 
#define VARARG(base, ...) VARARG_IMPL(base, VA_NARGS(__VA_ARGS__), __VA_ARGS__) 

,並調用它的使用例子:

#define sw_Logging_defineKeys(defineKeyValue) \ 
/** start of key list for sw_Logging_ **/\ 
/**/defineKeyValue(sw_Logging_,log)\ 
/**/defineKeyValue(sw_Logging_,time)\ 
/**/defineKeyValue(sw_Logging_,message)\ 
/**/defineKeyValue(sw_Logging_,object)\ 
/**/defineKeyValue(sw_Logging_,findCallStack)\ 
/**/defineKeyValue(sw_Logging_,debugging)\ 
/**/defineKeyValue(sw_Logging_,callStackSymbols)\ 
/**/defineKeyValue(sw_Logging_,callStackReturnAddresses)\ 
/** end of key list for sw_Logging_ **/ 
sw_Logging_defineKeys(definePrefixedKeys_in_h_File); 

最後一部分可能會有點困難周圍讓你的頭。 sw_Logging_defineKeys()宏定義了一個列表,它將一個宏的名稱作爲參數(defineKeyValue),然後用它來調用執行實際定義過程的宏。即對於列表中的每個項目,如果您瞭解目標c文件擴展名,則傳入的宏名稱用於定義上下文(「標題」或「實現」,例如「h」或「m」文件)雖然這用於目標c,但它僅僅是普通的舊c宏,用於「更高的用途」,比有史以來設想的Kernighan and Richie。 :-)

1

不,你不能在宏的替換列表中#表示QUOTE NEXT TOKEN。這更像是一個拼寫問題,而不是任何邏輯謎題:)

(如果您在代碼中需要這種解決方案,比使用宏的方法和技巧還要多,但需要具體說明用例需要 - 因爲你的例子可以通過定義來實現:#定義的myKey「值」)

這是從ANSI C99標準

6.10.3.2 The # operator

Constraints

1 Each # preprocessing token in the replacement list for a function-like macro shall be followed by a parameter as the next preprocessing token in the replacement list. Semantics 2 If, in the replacement list, a parameter is immediately preceded by a # preprocessing token, both are replaced by a single character string literal preprocessing token that contains the spelling of the preprocessing token sequence for the corresponding argument. Each occurrence of white space between the argument’s preprocessing tokens becomes a single space character in the character string literal. White space before the first preprocessing token and after the last preprocessing token composing the argument is deleted. Otherwise, the original spelling of each preprocessing token in the argument is retained in the character string literal, except for special handling for producing the spelling of string literals and character constants: a \ character is inserted before each " and \ character of a character constant or string literal (including the delimiting " characters), except that it is implementation-defined whether a \ character is inserted before the \ character beginning a universal character name. If the replacement that results is not a valid character string literal, the behavior is undefined. The character string literal corresponding to an empty argument is "". The order of evaluation of # and ## operators is unspecified.