トップ回答者
インクリメント+代入演算子でのC#とC++の演算結果の違い

質問
回答
-
外池です。
少なくとも、CやC++では、ひとつの式で、同一の変数が2回変更される場合であって、その順序が明快に定義されていない場合は、「未定義」ということになります。やってはいけません。
今回の場合ですと、右辺だけに着目すれば、代入操作のための評価結果ゼロを得てから、++が行われる。これは保証されています。(後置++の動作の定義) しかし、評価結果の左辺への代入と、右辺における++が、どちらが先になるかは、CやC++では定義がないようなので、結果はなんとも言えません。
お示し頂いたC++の方の「1」という結果はコンパイラがどのように解釈するかに依存します。最適化のオプションによって変わってしまうかもしれません。「たまたま」そうなった、ということで。
C#については、さらに明快な規定があるのかもしれませんが・・・、まだ、調べていません。
-
インクリメント命令の "設定" 部分をいつ実行するかを指定しないからだそうです。
http://msdn2.microsoft.com/ja-jp/library/ms173145(VS.80).aspx
すべての返信
-
外池です。
少なくとも、CやC++では、ひとつの式で、同一の変数が2回変更される場合であって、その順序が明快に定義されていない場合は、「未定義」ということになります。やってはいけません。
今回の場合ですと、右辺だけに着目すれば、代入操作のための評価結果ゼロを得てから、++が行われる。これは保証されています。(後置++の動作の定義) しかし、評価結果の左辺への代入と、右辺における++が、どちらが先になるかは、CやC++では定義がないようなので、結果はなんとも言えません。
お示し頂いたC++の方の「1」という結果はコンパイラがどのように解釈するかに依存します。最適化のオプションによって変わってしまうかもしれません。「たまたま」そうなった、ということで。
C#については、さらに明快な規定があるのかもしれませんが・・・、まだ、調べていません。
-
インクリメント命令の "設定" 部分をいつ実行するかを指定しないからだそうです。
http://msdn2.microsoft.com/ja-jp/library/ms173145(VS.80).aspx
-
επιστημηさん、外地さん、GENZ0さん
返答ありがとうございます。
「未定義」ということに関しネットで少し調べてみましたが、
ちょっと理解ができない部分もあり、今のところεπιστημηさんがおっしゃっている「やってはいけないこと」として解釈しました。
>右辺における++が、どちらが先になるかは、CやC++では定義がないようなので、結果はなんとも言えません。
そういうことなのですね。
(もちろんC#においても「未定義」は存在するのですね。)
この結果は「たまたま」そうなった結果ということなんですね。
「未定義」というのが今回の私のひとつの教訓となりました。
ありがとうございました。
-
外池です。
「未定義」という言葉・・・、「約束がありません」というか「決められていません」という感じでしょうか? 今回の例で、もちろん、aが4になったり5になったりすることはないのですが、1になるか、0になるかは、決められていません、ということで・・・。
もっとわかりやすい例があります。
i=5;
a = func1(++i) + func2(++i);
というような場合に、func1(6) + func2(7) になるのか、func1(7) + func2(6) になるのか、コンパイラーを作った人次第、ということになります。
同じ条件で、同じコンパイラーでコンパイルすれば、おそらく、同じ値が再現するはずです。コンパイルするごに、実行するごとに、コロコロ変わることはないとは思いますが・・・、それも、確実ではありません。
-
外池 さんからの引用 「未定義」という言葉・・・、「約束がありません」というか「決められていません」という感じでしょうか? 今回の例で、もちろん、aが4になったり5になったりすることはないのですが、1になるか、0になるかは、決められていません、ということで・・・。
特定のコンパイラの特定のバージョンであれば、コロコロ変わるようなことは無いでしょう。たぶん。
コンパイラを特定しないで言う場合、4になるかもしれませんし、5になるかもしれませんし、2681になるかもしれませんし、突然HDDがフォーマットされるかもしれませんし、突然お母さんに買い物を言いつけられるかもしれません。
言語規格における未定義ってのはそういうもんです。
ま、「やらない方がいい」という一言に集約されてしまうのですけど。
-
結果が未定義・・・、となると、4、5、2681・・・、何になるか、わからない。初期化してない変数の内容が「未定義」というやつは、ほんとに中に何が入っているか、わかりませんよね。
実行順序が未定義・・・、となると、まぁ、0か1か。(この場合)
オカンの買い物の言いつけなら、平和だし、喜んでいきますが(笑) 「未定義」が原因で、どこかのシステムがトラブって、飛行機が落ちてきた、とかになったら、笑えません(汗) 昔々、プログラムのハイフンひとつの間違いで、ロケットの打ち上げに失敗したとかいう話は聞きますが。
すいません、脱線が過ぎました。(話題の展開は、未定義)
-
インクリメント命令の "設定" 部分をいつ実行するかを指定しないからだそうです。
http://msdn2.microsoft.com/ja-jp/library/ms173145(VS.80).aspx
その部分はVS2008のドキュメントでは、2008年7月付けで「未定義の出力について誤りのある説明を削除」(履歴欄)ということで削除されました。
a = a++;
は、C#では、a自体を1増やしてから、a++の評価として1増やす前の値を確定し、その値(1増やす前の値)を左辺のaに代入することになります。(C#言語仕様v1.0の7.5.9)
ついでに。
i = 5;
a = func1(++i) + func2(++i);
は、オペランドの評価順序はC#では左からと決まっているので、
a = func1(6) + func2(7);
となります。
biac [ http://bluewatersoft.cocolog-nifty.com/ ]