私はこのコードの出力について混乱しています:
int c=3;
cout<<(c++)*(c++);
私はgccを使用し、出力はです9
が、誰かがそれは未定義の動作だと言いました、なぜですか?
私はこのコードの出力について混乱しています:
int c=3;
cout<<(c++)*(c++);
私はgccを使用し、出力はです9
が、誰かがそれは未定義の動作だと言いました、なぜですか?
問題は「シーケンスポイント」です。
http://en.wikipedia.org/wiki/Sequence_point
命令型プログラミングのシーケンスポイントは、以前の評価のすべての副作用が実行され、後続の評価からの副作用がまだ実行されていないことが保証される、コンピュータープログラムの実行の任意のポイントを定義します。
シーケンスポイントは、同じ変数が1つの式内で複数回変更された場合にも機能します。よく引用される例は、C式i = i ++です。これは、明らかにiに前の値を割り当て、iを増分します。iの最終的な値はあいまいです。これは、式の評価の順序によっては、割り当ての前、後、またはインターリーブで増分が発生する可能性があるためです。特定の言語の定義は、可能な動作の1つを指定する場合や、単に動作が未定義であると言う場合があります。CおよびC++では、このような式を評価すると未定義の動作が発生します。[1]
たまたま、MSVC(Windows)とgcc(Linux)の両方でまったく同じ答え(「9」)が得られます。また、gcc( "C")とg ++(C ++)のどちらでコンパイルしても警告が表示されます。
$ g++ -o tmp -Wall -pedantic tmp.cpp
tmp.cpp: In function "main(int, char**)":
tmp.cpp:7: warning: operation on "c" may be undefined
$ ./tmp
c=9...
未定義の動作は、何かが起こる可能性があることを意味します。
出力はですが9
、コンパイラーまたはコンパイラー・スイッチが異なると、、、またはになる可能性が12
あり0
ます2147483647
。
C仕様では、多くのことが未定義のままであり、言語を実装する人(つまり、コンパイラーを作成する人)の裁量にほとんど任されています。これらの未定義のものの中には、式のさまざまな部分の評価の順序があります。
たとえば、乗算は最初に計算され、次に両方の++
esが計算されますか、それとも一方が++
最初に計算され、次に乗算、次にもう一方が計算され++
ますか?
コンパイラの記述方法、コンパイルに使用されるフラグ、月の満ち欠けなどに応じて、答えは9、16、20になるか、鼻の悪魔が生成される可能性があります。混乱を招くコードや未定義の動作は常に避けてください。これを回避する方法については、シーケンスポイントを調べてください。
unspecified behavior
シーケンスポイントと、例に両方がある理由について考える1つの方法は、undefined behavior
最初に一時変数を導入する実装を検討することです。
このような実装では、ポストインクリメントを次のように処理できます。
tmp_1=c; // read 'c'
tmp_2 = tmp_1 + 1; // calculate the incremented value
c = tmp_2; // write to 'c'
tmp_1; // the result of the expression
元の式(c++)*(c++)
には2つのシーケンスがあります。
lhs_1=c; // read 'c'
lhs_2 = lhs_1 + 1; // calculate the incremented value
c = lhs_2; // write to 'c'
lhs_1; // the resulting value of the expression
rhs_1=c; // read 'c'
rhs_2 = rhs_1 + 1; // calculate the incremented value
c = rhs_2; // write to 'c'
rhs_1; // the resulting value of the expression
順序は次のとおりです。
lhs_1=c; // read 'c'
lhs_2 = lhs_1 + 1; // calculate the incremented value
c = lhs_2; // write to 'c'
rhs_1=c; // read 'c'
rhs_2 = rhs_1 + 1; // calculate the incremented value
c = rhs_2; // write to 'c'
lhs_1 * rhs_1 // (3 * 4) new value of 'c' is 5
または:
lhs_1=c; // read 'c'
rhs_1=c; // read 'c'
lhs_2 = lhs_1 + 1; // calculate the incremented value
c = lhs_2; // write to 'c'
rhs_2 = rhs_1 + 1; // calculate the incremented value
c = rhs_2; // write to 'c'
lhs_1 * rhs_1 // (3 * 3) new value of 'c' is 4
または:
rhs_1=c; // read 'c'
rhs_2 = rhs_1 + 1; // calculate the incremented value
c = rhs_2; // write to 'c'
lhs_1=c; // read 'c'
lhs_2 = lhs_1 + 1; // calculate the incremented value
c = lhs_2; // write to 'c'
lhs_1 * rhs_1 // (4 * 3) new value of 'c' is 5
....等。
これunspecified behavior
は、最初にlhsまたはrhsを評価できるということです。これは、中間のシーケンスポイントなしundefined behavior
で読み取りと書き込みを行っているということです。c