皆さん、次のコードで、2 番目の式の後の d の結果はどうなるでしょうか?
int d = 1;
d += d++;
その後、d は 3 であると想定しますが、単項インクリメント d++ は有効にならず、d の値は 2 のままです。
このバグに名前はありますか?C# のような単項インクリメントをサポートする他のコンパイラには存在しますか?
皆さん、次のコードで、2 番目の式の後の d の結果はどうなるでしょうか?
int d = 1;
d += d++;
その後、d は 3 であると想定しますが、単項インクリメント d++ は有効にならず、d の値は 2 のままです。
このバグに名前はありますか?C# のような単項インクリメントをサポートする他のコンパイラには存在しますか?
これはバグではなく、期待どおりに動作します。
+= 演算子は次のように展開されます。
d = d + d++;
つまり、++ 演算子によって引き起こされる変更は、結果が変数に代入されるときに上書きされます。
生成された IL を見ると、結果が 3 ではなく 2 である理由がわかります。
IL_0000: ldc.i4.1 // load constant 1 on evaluation stack
IL_0001: stloc.0 // pop and store value in local 0
IL_0002: ldloc.0 // load value of local 0 on evaluation stack
IL_0003: ldloc.0 // repeat, stack is now 1, 1
IL_0004: dup // duplicate topmost value on evaluation stack,
// i.e. stack is now 1, 1, 1
IL_0005: ldc.i4.1 // load constant 1 on evaluation stack
IL_0006: add // add two topmost values on stack,
// i.e. 1 and 1 and push result on stack
IL_0007: stloc.0 // pop and store this value in local 0
IL_0008: add // add the two remaining values on the stack
// which again happens to be 1 and 1 and push result to stack
IL_0009: stloc.0 // pop and store this value in local 0
つまり、格納される最終的な値は 1 と 1 の合計です。
(上記のコードはリリース モード ビルドのものです)
このようにコードを書き直すと、d の値が 3 に設定されます。
int d = 1;
d += ++d;
例がそのように動作する理由については、++ 演算子のドキュメントを参照してください。
抜粋:
2 番目の形式は、後置インクリメント操作です。演算の結果は、インクリメントされる前のオペランドの値です。
@Guffaが指摘したように、これはバグではなく、後置インクリメント操作の結果が操作d
によって上書きされているだけ+=
です。
++ 演算子が「壊れている」という質問を頻繁に受け取ります。ほとんどの場合、C++ のように動作が明確に定義されていない言語での動作に、質問者が慣れているためです。このようなシナリオについて書いた最近の記事を次に示します。
http://blogs.msdn.com/ericlippert/archive/2009/08/10/precedence-vs-order-redux.aspx
++dを試しましたか?d++ は後で評価されませんか?
に格納される最終結果は同じですが、の動作はd++
とは異なると思います。++d
d
愚かなコードは予測不可能です。お勧めかも
d += 2;
d++ と ++d は異なります。「 Select Isn't Broken」とも呼ばれます。
...そして、これは、ポスト/プリインクリメント/デクリメント演算子が他の演算子と一緒に式で使用されたときに非常に読みにくいことがわかった理由の例です。あなたが説明した動作は正しいですが、推論するのが難しく、誤解やバグにつながります.
ややこしいですが、以下のように書き直します。
int d = 1;
d += d;
++d;
コンパイラが古い値のコピーを保持する必要があると判断しないように、ポスト インクリメントの代わりにプレ インクリメント演算子を使用していることに注意してください。