正確には、二重文字列化のトリックはどのように機能しますか?


84

少なくとも一部のCプリプロセッサでは、マクロを文字列化する関数のようなマクロから別のマクロに渡すことで、マクロの名前ではなく値を文字列化できます。

#define STR1(x) #x
#define STR2(x) STR1(x)
#define THE_ANSWER 42
#define THE_ANSWER_STR STR2(THE_ANSWER) /* "42" */

ここでの使用例の例。

これは、少なくともGCCとClang(両方とも-std=c99)では機能しますが、C標準の用語でどのように機能するかはわかりません。

この動作はC99によって保証されていますか?
もしそうなら、C99はどのようにそれを保証しますか?
そうでない場合、動作はどの時点でC定義からGCC定義に移行しますか?


1
「少なくともいくらか」と言えば、それが機能しないものを見たことがあるということですか?ベンダーにバグレポートを書いてみたいと思います。
イェンス

@イェンス:いいえ; 私はしていません。私が使用したすべてのコンパイラー(つまり、GCCとClang)は、この動作を実装しています。
Peter Hosey

回答:


80

はい、保証されています。

これは、マクロへの引数自体がマクロ展開されているために機能します。ただし、マクロ引数名が文字列#またはトークンパスター##とともにマクロ本体に表示される場合を除きます。

6.10.3.1 / 1:

...関数のようなマクロを呼び出すための引数が識別された後、引数の置換が行われます。置換リストのパラメーターは、前に#または##前処理トークンが続くか、または##前処理トークンが後に続く場合を除き(以下を参照)、そこに含まれるすべてのマクロが展開された後、対応する引数に置き換えられます。

したがって、STR1(THE_ANSWER)そうすると、STR1の引数がマクロ展開されないため、「THE_ANSWER」が得られます。ただし、STR2の引数は、STR2の定義に代入されるマクロ展開されるため、STR1に引数が与え42られ、結果は「42」になります。


21

スティーブが指摘するように、これは保証されており、C89標準(これはマクロのおよび##演算子をコード化した標準であり、マクロを引数で再帰的に展開してから、次の場合にのみ本体に代入することを義務付けています)から保証されています。本文は引数にまたは##を適用しません。この点で、C99はC89から変更されていません。


それがC89の一部であることを確認するために時間を割いて+1。私たちの中には、C89モードでコンパイルする人が使用できるコードを作成するなど、移植性に関心を持っている人もいます-ほんの数年前、gccリリースはまだデフォルトでC89(さらに公平に言えばgcc拡張)であり、最後に聞いたMSVCはまだC89のみをサポートし、組み込みですまたはレガシーシステムには、C89コンパイラしかない場合もあります。C89は、優れた移植性のある「1階」を実現します。これは、今日の実用的なあらゆる目的でコンパイルおよび実行することを目標にできる、最も一般的でない分母標準です。ですから、それが記憶されているのを見るのはとてもうれしいです。
mtraceur
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.