• ベストアンサー

インクリメント++の計算

インクリメントの前置きと後置きの計算の考え方がいまいち飲み込めないですが 例:int a=5 , w; w=++a + a++;   printf("w=%d. a=%d",w,a); このときのwの値とaの値は? (一応試してみたらw=12 a=7になりましたがなぜでしょう?)

質問者が選んだベストアンサー

  • ベストアンサー
回答No.3

この式で、w=12 a=7 になったのは たまたま、そのコンパイラで、その オプションだったらそうなったという だけのことで、No.2 の回答にあるよ うに、「未定義動作」=コンパイラ によって、どんな結果になるかわから ないというのが正解です。 さて、++ の前置と後置の区別は、正 式には以下のようになります。 前置(たとえば、++a) ・式の値は、a をインクリメントしたもの ・副作用として、a そのものをインクリメ  ントする ・動作の順序は規定しない 後置(たとえば、a++) ・式の値は、a の値そのもの ・副作用として、a そのものをインクリメ  ントする ・動作の順序は規定しない ということで、時々入門書に書いてあるよ うに、「インクリメントしてから評価」と か、「評価してからインクリメント」とい うことまでは規定されていません。 ※ただし、規定通りの動作をさせる方法の ひとつではあります。 そして、「副作用として、a をのものをイ ンクリメント」というのが、確実に行われ るのが、No.2 の回答にある、「副作用完 了点」で、大抵の場合(例外あり)は、 ; までになります。 つまり、 a = 5; w = ++a; なら、 w == 6 (式の値は、インクリメント後) a == 6 (副作用として、a をインクリメント) a = 5; w = a++; なら、 w == 5 (式の値は、インクリメント前) a == 6 (副作用として、a をインクリメント) となります。 実際、こういう式であれば、インクリメント してから評価という解釈をしても、同じ動作に なります。 一方、 w=++a + a++; という式は、たとえば、代表的なもので以下の ような動作をします。 (例1) ・++a の時点で、評価とインクリメント完了  (この評価完了の時点で、a = 6) ・a++ の時点で、評価とインクリメント完了  (この評価完了の時点で、a = 7) ・結果として、 w = 6 + 6 = 12 a = 7 (例2) ・++a の時点で、評価は完了ただし、インクリ  メントはしない(副作用完了時点までにイン  クリメント完了すればいいから)  この時点で、a == 5 のまま ・a++ の時点で、評価は完了ただし、インクリ メントはしない(同上)  この時点で、a == 5 のまま ・計算結果を w に代入 ・最後に、インクリメント実施(この後、a == 7) ・結果として、 w = 5 + 6 = 11 a = 7 (例3) ・基本的な流れは、例2と同じ。  ただし、インクリメントは、1回だけ ・結果として、 w = 5 + 6 = 11 a = 6 そのほかにも、いろいろな可能性があります。 そして、w = ++a + a++; だと、上記のように いろいろな結果が出る可能性がありますが、 w = (++a) * 2; とか w = (a++) + (+bb); とか、 正しい式であれば、例(1~3)のいずれでも 同じ結果になることがわかると思います。

poyo3
質問者

お礼

未定義だと成り行きで変わってしまうのですね。 回答ありがとうございます。

その他の回答 (4)

  • jacta
  • ベストアンサー率26% (845/3158)
回答No.5

未定義の動作である以上、処理系を特定し、処理系のドキュメントに具体的な振る舞いが規定されていないかぎり、それ以上の議論は無意味です。 未定義の動作の場合、コンパイルできるかどうかも含めて、どうなるか分からないのです。

poyo3
質問者

お礼

そういうものなんですね。回答ありがとうございました。

回答No.4

まず「加算(+)の右辺と左辺は、どっちが先に計算されるか判らない」です。 ・ケース1 インクリメントは即時に実行し、右辺から先に計算するコンパイラの場合。 まず、右辺のa++が計算されます。この式の値は「インクリメントする前の値」を持ちますから「右辺の値は5」です。そして、aがインクリメントされて6になりますが、その6という値は使われません。 次に、左辺の++aが計算されます。この式は「インクリメントした後の値」を持ちますから、まず6になってるaがインクリメントされて7になり、その7という値が式の値になり「左辺の値は7」です。 これで5と7が求まったので、足し算されて12になります。 ・ケース2 インクリメントは即時に実行し、左辺から先に計算するコンパイラの場合。 まず、左辺の++aが計算されます。この式は「インクリメントした後の値」を持ちますから、まずaがインクリメントされて6になり、その6という値が式の値になり「左辺の値は6」です。 次に、右辺のa++が計算されます。この式の値は「インクリメントする前の値」を持ちますから「右辺の値は6」です。そして、aがインクリメントされて6になりますが、その6という値は使われません。 これで6と6が求まったので、足し算されて12になります。 次に「あとでインクリメント」は「式中の、どの位置でインクリメントしても良い」のです。逆に言えば「どの位置でインクリメントされるか判らない」のです。 ・ケース3 a++で、インクリメントをすぐに行わないコンパイラの場合。 もし、a++でインクリメントするのを「加算が終了したあと」に行うコンパイラの場合、加算の右辺と左辺のどちらを先に計算しても「加算が終了したあとに行うインクリメント」は加算結果に含まれないので、wは11になるでしょう。 ・ケース4 上記以外。 ---- で、今回は、偶然、ケース1かケース2のどちらかになったようですが、どっちになったかは判りません。もしかしたらケース4で、結果も偶然なのかも。

poyo3
質問者

お礼

そうでしたか。回答ありがとうございます。

  • jacta
  • ベストアンサー率26% (845/3158)
回答No.2

> 例:int a=5 , w; > w=++a + a++; >   printf("w=%d. a=%d",w,a); > このときのwの値とaの値は? 未定義の動作になります。 副作用完了点から次の副作用完了点までの間に、同じオブジェクトを複数回更新してはいけません。

poyo3
質問者

お礼

なるほど。そういうものなんですね。回答ありがとうございます。

  • TinyPine
  • ベストアンサー率30% (719/2386)
回答No.1

前に置くのは先に加算されます 後に置くのは後に加算されます。 w=++a  ここで、aは5に1加算された6に成ります +  a++ ここで wには aの現在値である6が加算されます、その後1加算されます; 従ってw = 12 aには最後のaの値、7が結果として表示されます。

poyo3
質問者

お礼

そういうことでしたか。回答ありがとうございます。

関連するQ&A

専門家に質問してみよう