我最近在我的 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 行,首先计算括号,使用
int
s 作为中间结果,导致溢出并存储 -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 给我的任何东西都是正确的(因为这是未定义的)?