6

これらのコードブロックが異なる結果をもたらすのはなぜですか?

いくつかの一般的なコード:

#define PART1PART2 works
#define STRINGAFY0(s) #s
#define STRINGAFY1(s) STRINGAFY0(s)

ケース1:

#define GLUE(a,b,c) a##b##c  
STRINGAFY1(GLUE(PART1,PART2,*))
//yields
"PART1PART2*"

ケース2:

#define GLUE(a,b) a##b##*
STRINGAFY1(GLUE(PART1,PART2))
//yields
"works*"

ケース3:

#define GLUE(a,b) a##b
STRINGAFY1(GLUE(PART1,PART2*))
//yields
"PART1PART2*"

VS.net2005sp1のMSVC++を使用しています

編集:現在、マクロを展開するときにプリプロセッサが次のように機能すると信じています。ステップ1:-本文を取得します-##演算子の周りの空白を削除します-文字列を解析します。パラメーター:-##演算子の隣にある場合は、識別子をパラメーターのリテラル値(つまり、渡された文字列)に置き換えます。-##演算子の隣にない場合は、この説明プロセス全体を最初にパラメータの値を入力してから、識別子をその結果に置き換えます。(stringafyシングル'#'ケースatmを無視します)-すべての##演算子を削除します

ステップ2:-結果の文字列を取得し、マクロを解析します

さて、それから私は3つのケースすべてがまったく同じ結果の文字列を生成するはずだと信じています:

PART1PART2 *

したがって、ステップ2の後、結果は次のようになります。

動作します*

しかし、少なくとも同じ結果になるはずです。

4

2 に答える 2

3

*ケース1と2は、 1つのプリプロセッサトークンにを貼り付けようとしているため、動作は定義されていません。PART1PART2プリプロセッサの相関ルールによれば、これはトークン(または単にPART2)とを接着しようとし*ます。あなたの場合、これはおそらく黙って失敗します。これは、物事が定義されていない場合に考えられる結果の1つです。トークンのPART1PART2後に続くもの*は、マクロ展開の対象とは見なされません。次に、Stringficationは、表示される結果を生成します。

私のgccは、あなたの例では異なった振る舞いをします:

/usr/bin/gcc -O0 -g -std=c89 -pedantic   -E test-prepro.c
test-prepro.c:16:1: error: pasting "PART1PART2" and "*" does not give a valid preprocessing token
"works*"

したがって、ケース1を要約すると、2つの問題があります。

  • 有効なプリプロセッサトークンにならない2つのトークンを貼り付けます。
  • ##オペレーターの評価順序

ケース3の場合、コンパイラは間違った結果を出します。そうすべき

  1. の引数を評価する STRINGAFY1
  2. それをするためにそれは拡大しなければなりませんGLUE
  3. GLUE結果はPART1PART2*
  4. もう一度拡張する必要があります
  5. 結果はworks*
  6. その後、に渡されます STRINGAFY1
于 2010-07-19T08:09:31.153 に答える
1

それはあなたがそれをするように言っていることを正確にやっています。1番目と2番目は、渡されたシンボル名を取得し、それらを一緒に新しいシンボルに貼り付けます。3番目は2つの記号を取り、それらを貼り付けます。次に、文字列に*を自分で配置します(最終的には別の記号に評価されます)。

結果の質問は正確には何ですか?何を期待していましたか?私が期待するように、すべてが機能しているようです。

それならもちろん、なぜとにかくこのようなシンボルの暗黒の芸術で遊んでいるのかという問題です。:)

于 2010-07-19T07:17:25.070 に答える