9

gcc プリプロセッサと MS VS cl の違いがもう 1 つあります。次のスニペットを検討してください。

# define A(x) L ## x
# define B A("b")
# define C(x) x
C(A("a" B))

「gcc -E」の場合、次の結果が得られます。

L"a" A("b")

「cl /E」の場合、出力は異なります。

L"a" L"b"

MS プリプロセッサは何らかの方法で追加のマクロ展開を実行します。gccとは明らかに動作のアルゴリズムが異なりますが、このアルゴリズムも秘密のようです。観測された違いをどのように説明できるか、また MS cl での前処理のスキームを知っている人はいますか?

4

3 に答える 3

4

GCCは正しいです。規格では次のように規定されています。

C99 6.10.3.4/2 (および C++98/11 16.3.4/2) : この置換リストのスキャン中に置換されるマクロの名前が見つかった場合 (ソース ファイルの残りの前処理トークンは含まれません) )、置き換えられません。

したがって、 を展開するときA("a" B)は、まず を に置き換えBますA("a" A("B"))

A("B")は、引用された規則に従って置き換えられないため、最終結果はL"a" A("B")です。

于 2012-07-13T12:24:03.673 に答える
3

マイクの答えは正しいですが、彼は実際には、これがそうである理由を示す標準の重要な部分を省略しています。

6.10.3.4/2置換リスト (ソース ファイルの前処理トークンの残りを含まない) のこのスキャン中に置換されるマクロの名前が見つかった場合、それは置換されません。さらに、ネストされた置換が置換されるマクロの名前に遭遇した場合、それは置換されません。これらの置換されていないマクロ名の前処理トークンは、マクロ名の前処理トークンが置換されていたコンテキストで後で (再) 検査されたとしても、さらに置換することはできません。

ここで強調した最後の節に注意してください。

したがって、gcc と MSVC の両方がマクロA("a" B)L"a" A("b")に展開しますが、興味深いケース (MSVC が台無しになる) は、マクロがマクロによってラップされる場合Cです。

マクロを展開するときは、展開するCマクロの引数が最初に調べられ、展開されますA。次に、これが C の本体に代入され、その本体が再度スキャンされてマクロが置換されます。Cこれは の展開なので、名前だけがスキップされると思うかもしれませんがC、この最後の句は、 の展開からのトークンAも A の再展開をスキップすることを意味します。

于 2012-07-13T19:29:54.783 に答える
0

A マクロの残りの出現を置き換える必要があると考える方法には、基本的に 2 つの方法があります。

1 つ目は、マクロの置換リスト内の対応するパラメーターの代わりに挿入される前の処理引数またはマクロ引数です。通常、各引数は、標準のセクション 6.10.3.1 で説明されているように、入力ファイルの残りの部分を形成しているかのように完全にマクロ置換されます。ただし、パラメータ (ここでは x) が ## の隣にある場合、これは行われません。この場合、パラメータは単純に 6.10.3.3 に従って引数に置き換えられ、再帰的なマクロ置換は行われません。

2 番目の方法は、セクション 6.10.3.4 の「再スキャンとさらなる置換」ですが、これは、一度置換されたマクロに対して再帰的に行われるわけではありません。

したがって、この場合はどちらも当てはまりません。つまり、gcc は A を置換せずにそのままにしておくのが正しいということです。

于 2012-07-13T12:51:41.280 に答える