整数溢出和操作顺序

时间:2016-01-15 13:02:46

标签: c++ operators language-lawyer multiplication associativity

我最近遇到了一个关于我的C ++代码的问题让我想知道我是否对编译器对长操作有什么误解... 只需看看以下代码:

int

对于我来说,在这3行中的任何一行中发生乘法的顺序是不确定的。但是,这是我认为会发生的事情(假设long long是32b,int是64b,它们都遵循IEEE规则):

  • 对于第2行,首先评估括号,使用long long s作为中间结果,导致溢出并存储-1073741824。对于最后一次乘法,此中间结果将提升为long long,因此打印结果应为-5368709120。
  • 第1行和第3行是#34;等同于#34;由于评估顺序未定义。

现在,对于第1行和第3行,我不确定:我认为虽然评估顺序未定义,但编译器会#34;促进"所有操作都是最大操作数的类型,即~/tmp$ g++-5 cast.cc ~/tmp$ ./a.out -5368709120 -5368709120 16106127360 。因此,在这种情况下不会发生溢出,因为所有的计算都是在64b中进行的......但这就是GCC 5.3.0给我的代码:

{{1}}

我也期望第一个结果是16106127360。由于我怀疑在GCC中存在如此大规模的编译器错误,我猜错误在于键盘和主席之间。

任何人都可以确认/确认这是未定义的行为,并且GCC在给我任何它给出的任何内容时都是正确的(因为这是未定义的)?

2 个答案:

答案 0 :(得分:7)

海湾合作委员会是正确的。

  1. 乘法的相关性为left to right。这意味着所有这些表达式都是从左到右计算的。
  2. 升级到更高类型只在两个不同类型的二元运算符的操作数之间。
  3. 例如,第一个表达式被解析为i * j * k * n * l = ((((i * j) * k) * n) * l),并且只有在计算了最后一个乘法时才会进行提升,但此时左操作数已经不正确。

答案 1 :(得分:3)

标准明确地将分组定义如下:

  

5.6乘法运算符[expr.mul]

     

1乘法运算符*,/和%group从左到右。

这意味着a * b * c被评估为(a * b) * c。符合标准的编译器无权将其评估为a * (b * c)