90
int main ()
{
   int a = 5,b = 2;
   printf("%d",a+++++b);
   return 0;
}

このコードでは、次のエラーが発生します。

エラー: インクリメント オペランドとして左辺値が必要です

しかし、 と の間にスペースを入れるa++ +++b、正常に動作します。

int main ()
{
   int a = 5,b = 2;
   printf("%d",a++ + ++b);
   return 0;
}

最初の例のエラーはどういう意味ですか?

4

9 に答える 9

182

コンパイラは段階的に書かれています。最初の段階は字句解析器と呼ばれ、文字を記号構造に変換します。したがって、「++」はenum SYMBOL_PLUSPLUS. その後、パーサー ステージでこれを抽象構文ツリーに変換しますが、シンボルを変更することはできません。スペースを挿入することでレクサーに影響を与えることができます (引用符で囲まれていない限り、記号は終了します)。

通常のレクサーは (いくつかの例外を除いて) 貪欲であるため、コードは次のように解釈されます。

a++ ++ +b

パーサーへの入力はシンボルのストリームであるため、コードは次のようになります。

[ SYMBOL_NAME(name = "a"), 
  SYMBOL_PLUS_PLUS, 
  SYMBOL_PLUS_PLUS, 
  SYMBOL_PLUS, 
  SYMBOL_NAME(name = "b") 
]

構文的に間違っているとパーサーが考えているもの。(コメントに基づく編集: ++ を r 値に適用できないため、意味的に正しくありません。これにより、a++ が発生します)

a+++b 

a++ +b

どちらでも構いません。あなたの他の例もそうです。

于 2011-04-15T13:16:15.043 に答える
98

printf("%d",a+++++b);(a++)++ + bは、最大ムンク ルールに従って解釈されます。.

++(接尾辞) は an に評価されませんlvalueが、オペランドが an である必要がありlvalueます。

! 6.4/4 は、次の前処理トークンは、前処理トークンを構成できる最長の文字シーケンスであると述べています」

于 2011-03-17T15:40:15.000 に答える
30

レクサーは、一般に「最大ムンク」アルゴリズムと呼ばれるアルゴリズムを使用してトークンを作成します。つまり、文字を読み込んでいるときに、すでに持っているものと同じトークンの一部にできないものに遭遇するまで文字を読み続けます(たとえば、数字を読み取っていたので、数字になっている場合は、 、Aそれは数字の一部になり得ないことを知っているので、それは停止しA、次のトークンの開始として使用するために入力バッファに残します)。次に、そのトークンをパーサーに返します。

この場合、それはとし+++++てlexedされることを意味しa ++ ++ + bます。最初のポストインクリメントは右辺値を生成するため、2番目のポストインクリメントはそれに適用できず、コンパイラーはエラーを出します。

FWIWだけですが、C ++では、オーバーロードoperator++して左辺値を生成できます。これにより、これが機能します。例えば:

struct bad_code { 
    bad_code &operator++(int) { 
        return *this;
    }
    int operator+(bad_code const &other) { 
        return 1;
    }
};

int main() { 
    bad_code a, b;

    int c = a+++++b;
    return 0;
}

コンパイルして、私が手元にあるC ++コンパイラ(VC ++、g ++、Comeau)で実行します(ただし、何もしません)。

于 2011-04-15T14:07:16.007 に答える
12

コンパイラは必死に を解析しようとしa+++++b、 として解釈し(a++)++ +bます。現在、ポストインクリメント ( a++)の結果は左辺値ではありません。つまり、再度ポストインクリメントすることはできません。

製品品質のプログラムでそのようなコードを書かないでください。あなたのコードを解釈する必要があるあなたの後に来るかわいそうな仲間について考えてみてください。

于 2011-03-17T15:28:57.800 に答える
10
(a++)++ +b

a++ は前の値である右辺値を返します。これを増やすことはできません。

于 2011-03-17T15:27:36.317 に答える
7

未定義の動作を引き起こすためです。

どちらですか?

c = (a++)++ + b
c = (a) + ++(++b)
c = (a++) + (++b)

ええ、あなたもコンパイラもそれを知りません。

編集:

本当の理由は、他の人が言ったものです:

と解釈され(a++)++ + bます。

ただし、ポストインクリメントには左辺値(名前付きの変数)が必要ですが、(a ++)はインクリメントできない右辺値を返すため、エラーメッセージが表示されます。

これを指摘するために他の人に感謝します。

于 2011-04-15T13:11:47.047 に答える
5

コンパイラはそれを次のように認識していると思います

c = ((a++)++)+b

++変更可能な値をオペランドとして持つ必要があります。a は変更可能な値です。a++ただし、これは「右辺値」であるため、変更できません。

ちなみに、GCC C で表示されるエラーは同じですが、言葉遣いが異なります: lvalue required as increment operand.

于 2011-04-15T13:16:18.630 に答える