2011-09-24 18 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

プリプロセッサは、マクロを1回だけ決定しません。プリプロセッサでは#defineマクロと#defineマクロを複数回使用できます。処理中にマクロが変更されたり編集されたりするので、マクロ内でこれらのルールを編集することはできません。 – Linsey

+0

プリプロセッサは何らかの順序で「すべてのファイルを調べていくつかの文字列を置き換える」ことを行います。順序があるという事実は、メモリと#undef #ifdefなどを持つことができます。しかし、置換された文字列をマクロとして取得するには、再帰が必要です。 – Willy

+0

例を挙げてください。内側の '#define'より前のテキストを置き換えたいのであれば再帰が必要だと思っていますが、そのコードがそのポイントから有効になっていれば問題はないようです。 – Linsey

0

マクロは単純なテキスト置換です。マクロから新しいプリプロセッサディレクティブを生成するには、プリプロセッサでの置換処理の先頭にあるから前処理を続ける必要があります。しかし、標準化された前処理をの後ろに置き換えて、の後ろに置き換えます。

これは、未処理のコードを入力ストリームとして表示し、処理された(および置換された)コードを出力ストリームとして表示する、ストリーミングの観点から意味があります。マクロの置換は任意の長さを持つことができます。これは、最初から前処理を行うために、入力ストリームの先頭に任意の数の文字を挿入して再度処理する必要があることを意味します。

処理が置換の後に続く場合、入力はそのまま挿入されたりバッファリングされたりすることなく、1回の実行で処理されます。すべてが直接出力に送られるからです。

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のために使用されていますが、おそらくKernighan and Richieよりも "高い目的"のために使用されている単純な単純な古いcマクロです。 :-)

1

いいえあなたはできません - マクロの置換リストにはQUOTE NEXT TOKENを意味します。どのような論理的なパズルよりも、スペルの問題です。

(このような種類のソリューションが必要な場合は、マクロを使用する方法や方法がありますが、ユースケースについて具体的に説明する必要があります必要性 - あなたの例のように定義することによって達成することができます:それは、コンパイルのチャンスを持っているので、の#define 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.

関連する問題