2011-11-22 14 views
23

C++ FAQ - Miscellaneous technical issues - [39.6] What should be done with macros that need to paste two tokens together?なぜマクロに2層の間接指定が必要なのですか?で

は、誰かが私になぜを説明してもらえますか?私が読んだのはです。私はを信じていますが、誰かがそう言っていたので、何かを信じることはできません。

私はアプローチを試してみましたが、私はどんなバグが表示されて見つけることができません:だから

#define mymacro(a) int a ## __LINE__ 
mymacro(prefix) = 5; 
mymacro(__LINE__) = 5; 
int test = prefix__LINE__*__LINE____LINE__; // fine 

なぜ私は(Webページからの引用)の代わりに、このようにそれを行うために必要な操作を行います。

##を使用する場合、間接指定の二重のレイヤーが必要です。 は、基本的には、このような として「トークン貼り付け」のための特別なマクロを作成する必要があります。この上

#define NAME2(a,b)   NAME2_HIDDEN(a,b) 
#define NAME2_HIDDEN(a,b) a ## b 

トラスト私を - あなたは本当に これを実行する必要があります! (。。そして、誰もそれが時々 なし間接の第二層を作品と言って私を書きませんしてくださいLINE__ __ でシンボルを連結してみて、次に何が起こるかを参照)

編集:彼は使用していますなぜ誰も説明してもらえNAME2_HIDDENが宣言される前に? NAME2_HIDDENマクロを使用する前にそれを定義する方が論理的です。ここ何かのトリックですか?

+0

私はあなたに何を聞いているのか分かりません... –

+0

私は少しはっきりしていません。 – Rookie

+0

@tenfour、done。私の編集部分の答えを知っているかもしれませんか? – Rookie

答えて

29

C仕様の関連部分:

6.10.3.1引数置換

関数のようなマクロの呼び出しの引数が識別された後、 引数の置換が行われます。置換リストのパラメータは、#または##の前処理トークンまたは##前処理トークン(以下を参照)の前に、 が付いていない限り、 が展開された後に対応する引数で置き換えられます。置き換えられる前に、各引数の前処理トークンは 完全なマクロで置き換えられ、前処理ファイルの残りの部分を形成するかのように置き換えられます。他の 前処理トークンは利用できません。

あなたは二重の間接をしたいか否かを判断する重要な部分は、第二の文とその中の例外である - パラメータは、このようなmymacroNAME2_HIDDEN内のparamsとして(#または##操作に関与している場合)、引数内のその他のマクロは、#または##を実行する前に展開されません。一方、または##がマクロ本体に(NAME2のように)即座に存在しない場合は、パラメータ内の他のマクロが展開されます。

だから、すべてのマクロを最初に展開してから、#または##(二重層間接参照が必要な場合もあります)を実行し、最初にマクロを展開したくない場合があります(この場合、ダブルレイヤーマクロを使用することはできません。直接実行する必要があります)

+1

。私はそれが非常に私はいつもそれを使用するように言われたウェブサイトを妨害することがわかった...私の場合、私はそのようにそれを使用したいことはありません。 – Rookie

4

__LINE__は、現在の行番号を解決する特別なマクロです。しかし、__LINE__のトークンペーストを直接行うと、解決する機会が得られませんので、例えばprefix23の代わりにトークンprefix__LINE__で終わることになります。野生。

+0

編集:ああ待って、誰かが変数名に行番号を与えることを期待するだろうか?うーん。それが原因で起こるすべての問題ですか? – Rookie

+0

彼はなぜ彼が "間違った"順序でマクロを使用したのか説明できますか?例えば。彼はそれが宣言される前にマクロ 'NAME2_HIDDEN'を参照しています。それは良い習慣と考えられているのですか、それとも何らかのトリックですか?私は両方の方法をテストし、私は同じ結果を得るようです。 – Rookie

+0

マクロを任意の順序で定義することができますが、どちらも間違っていません。確かに –

3

Chris Doddは質問の最初の部分について優れた説明をしています。 2番目の部分については、定義シーケンスについては、短いバージョンは#defineのディレクティブ自体は評価されていません。シンボルがファイル内の他の場所に見つかった場合にのみ評価され、展開されます。例えば:それはAがファイルにその時点で定義されている方法であるため

#define A a //adds A->a to the symbol table 
#define B b //adds B->b to the symbol table 

int A; 

#undef A  //removes A->a from the symbol table 
#define A B //adds A->B to the symbol table 

int A; 
int A;

最初はint a;となります。 2番目のint A;は、2回の展開後にint b;になります。 Aはファイル内のその時点でBと定義されているため、最初はint B;に展開されます。プリプロセッサは、シンボルテーブルをチェックするときにBがマクロであると認識します。 Bbに展開されます。

重要なのは、定義がどこにあるかにかかわらず、展開の時点でのシンボルの定義だけです。

+1

オハイオ州、私はちょうどあなたがそれらを使用する順序でそれらを置くために、より論理的だろうと思った、どういうわけか私には意味をなさない。説明に感謝します。 – Rookie

1

マクロが宣言される順序は重要ではありません。使用される順序は重要です。実際に宣言される前にそのマクロを実際に使用していた場合(実際のコードでは、呼び出されるまで休止状態のマクロにはありません)、一種のエラーが発生しますが、ほとんどの正常な人々は実行しませんマクロを書いて、さらに定義されていないマクロを使用する関数などを書いています。あなたの質問は単なる1つの質問ではないようですが、私はただその部分に答えます。私はこれをもう少し壊したはずだと思います。

0

私はここのすべてのリンクから集められた最も技術的ではない回答であり、リンクのリンクは)単層間接macro(x) #xは入力されたマクロの名前をストリング化しますが、マクロの価値。 printf(myVarOneLayer)

printf(myVarOneLayer)で何が起こる

#define valueOfPi 3 
#define macroHlp(x) #x 
#define macro(x) macroHlp(x) 
#define myVarOneLayer "Apprx. value of pi = " macroHlp(valueOfPi) 
#define myVarTwoLayers "Apprx. value of pi = " macro(valueOfPi) 

printf(myVarOneLayer); // out: Apprx. value of pi = valueOfPi 
printf(myVarOTwoLayers); // out: Apprx. value of pi = 3 

は入力を文字列化するprintf("Apprx. value of pi = " macroHlp(valueOfPi))

macroHlp(valueOfPi)試行に展開され、入力自体は評価されません。人生の唯一の目的は、入力を受けて文字列化することです。それはそう"valueOfPi"

に展開して、何がprintf(myVarTwoLayers)

printf(myVarTwoLayers)で起こるがprintf("Apprx. value of pi = " macro(valueOfPi)

macro(valueOfPi)に展開されても、何の文字列化操作、すなわち無#xは、それが拡張年代に存在していませんが、そう、xありxを評価し、ストリング化のために値をmacroHlpに入力する必要があります。それはmacroHlp(3)に展開され、使用されているので番号3を文字列にします#x

関連する問題