16

それはC++std16.3.4で言います:

[マクロ呼び出しの置換からの]結果の前処理トークンシーケンスは、ソースファイルの後続のすべての前処理トークンとともに再スキャンされ、さらにマクロ名を置換します。

置換リストのこのスキャン中に置換されるマクロの名前が見つかった場合(ソースファイルの残りの前処理トークンは含まれません)、置換されません。

さらに、ネストされた置換で置換されるマクロの名前が検出された場合、そのマクロは置換されません。

これらの置換されていないマクロ名前処理トークンは、そのマクロ名前処理トークンが置換されていたコンテキストで後で(再)検査された場合でも、それ以上の置換には使用できなくなります。

ネストされたマクロ置換とは正確には何ですか?

具体的に次のことを考慮してください。

#define f(x) 1 x
#define g(x) 2 x

g(f)(g)(3)

私は次のことを期待していました:

g(f)(g)(3)    <-- first replacement of g, ok
2 f(g)(3)     <-- nested replacement of f, ok
2 1 g(3)      <-- second nested replacement of g, don't replace, stop

ただし、gccは予期せずgの2番目の置換を進め、次のように生成します。

2 1 2 3

何か案は?

アップデート:

多くの調査の後、より簡単な例でこの問題を解決しましょう。

#define A(x) B
#define B(x) A(x)

A(i)(j)

これは次のように拡張されます。

A(i)(j)
B(j)
A(j)

この規格ではA(j)、拡張する必要があるかどうかは指定されてBいません。A(j)委員会は、現実世界のプログラムがこの振る舞いに依存A(j)することは期待されていないため、このままにすることを決定しましたB

4

3 に答える 3

6

これは、元の意図と、この主題に関する説明が標準に追加されていない理由を説明しています。

http://open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#268


268.再スキャンされた置換テキストでのマクロ名の抑制

セクション:16.3.4 [cpp.rescan]     ステータス:オープン     送信:Bjarne Stroustrup     日付:2001年1月18日

次の例の結果がどうあるべきかは、規格からは明確ではありません。

#define NIL(xxx) xxx
#define G_0(arg) NIL(G_1)(arg)
#define G_1(arg) NIL(arg)
G_0(42)

規格の関連テキストは16.3.4[cpp.rescan]パラグラフ2にあります。

[切り取った]

の展開の順序は次のG0(42)とおりです。

G0(42)
NIL(G_1)(42)
G_1(42)
NIL(42)

問題はNIL、このシーケンスの最後の行での使用が、引用されたテキストの下での非置換の対象となるかどうかです。含まれている場合、結果はになりますNIL(42)。そうでない場合、結果は単純になります42

このテキストでのJ11委員会の当初の意図は42、その作成者であるDave Prosserによって提供された置換アルゴリズムの元の擬似コードの説明によって示されるように、結果がである必要があるということでした。ただし、英語の説明では、擬似コードの微妙な点の一部が省略されているため、この場合は間違いなく間違った答えが返されます。

推奨される解決策(Mike Miller):[snipped]

2004年4月のWG14会議からのメモ(トムプラム経由):

1980年代に、いくつかのWG14の人々は、「非置換」の言い回しと擬似コードを生成する試みとの間に小さな違いがあることを理解していました。委員会の決定は、「実際の」現実的なプログラムはこの分野に参入しないというものであり、不確実性を減らすことを試みることは、実装またはプログラムの適合状態を変更するリスクに値しません。

于 2013-03-28T00:45:11.890 に答える
0

g(x)常に。に置き換えられ2 xます。gの2番目のネストされた置換では、を使用g(x)して呼び出すx=3ため、これにより結果が生成され2 3ます。私の理解では、これが無限ループを生成する場合、コンパイラはマクロをその値に置き換えません。

#define g( x ) f( x )
#define f( x ) g( x )

g( 1 ) -- > f( 1 ) --> stop 
于 2013-03-23T07:43:32.640 に答える
0

「(ソースファイルの残りの前処理トークンは含まない)」と記載されているためです。の最初の置換は、gのみを参照してfください。これで、ファイルの残りの部分から取得した前処理トークンで置き換えることができますが、によって生成されfたプログラムレコードはどこにもありません。の置換は、同様に再帰によって汚染されていないを生成します。fgf(g)g

ネストされた置換は、トークンが別の置換から供給されたものではなく、別の置換によって囲まれたものです。後者の定義によれば、置換には、相互に排他的な複数のネストされた親が存在する可能性があります。

于 2013-05-22T08:26:26.027 に答える