私は最近、私の C++ コードで問題に直面し、コンパイラが長い操作で何をするかについて誤解しているのではないかと思いました...次のコードを見てください。
#include <iostream>
int main() {
int i = 1024, j = 1024, k = 1024, n = 3;
long long l = 5;
std::cout << i * j * k * n * l << std::endl; // #1
std::cout << ( i * j * k * n ) * l << std::endl; // #2
std::cout << l * i * j * k * n << std::endl; // #3
return 0;
}
私にとって、これらの 3 行のいずれかで乗算が発生する順序は定義されていません。int
ただし、これが私が予想したことです( 32b、long long
64bで、両方ともIEEEルールに従っていると仮定します):
- 2 行目では、中間結果として s を使用してかっこが最初に評価さ
int
れ、オーバーフローが発生して -1073741824 が格納されます。この中間結果は最後の乗算に昇格されるlong long
ため、出力される結果は -5368709120 になります。 - 評価の順序が定義されていないため、1 行目と 3 行目は「同等」です。
ここで、行 #1 と #3 については不明です。評価の順序は定義されていませんが、コンパイラはすべての操作を最大のオペランドの型、つまりlong long
ここに「昇格」させると思いました。したがって、この場合、すべての計算が 64b で行われるため、オーバーフローは発生しません...しかし、これは GCC 5.3.0 がこのコードに対して私に与えるものです:
~/tmp$ g++-5 cast.cc
~/tmp$ ./a.out
-5368709120
-5368709120
16106127360
最初の結果も 16106127360 と予想していました。GCC にこの規模のコンパイラのバグがあるとは思えないので、バグはキーボードと椅子の間にあると思います。
これは未定義の動作であり、GCCは私に与えるものは何でも正しいことを確認/確認してください(これは未定義であるため)?