签名整数溢出到负数:这是一个编译器错误,还是我误解了优化?

时间:2014-10-17 20:17:42

标签: c++ g++

以下C ++代码片段计算Fibonacci数字。对于32位整数,当n=47b变为负数时,我们会溢出。

int a=0, b=1, n=2;
do {
   a += b; int c = a; a = b; b = c;
   ++n;
} while ( b>0 and n<50 );
std::cout << "Ended at n=" << n << " b=" << b << std::endl;

在g ++ 4.9.1上编译一切都很顺利;除非我使用-O2-O3,否则循环会一直运行到n=50。编译器是否可能假设,ab开始为正且仅应用了添加,它们必须保持正数?查看装配输出确认条件b>0即使被检查也是如此。

g ++ 4.7.0也是如此。所以我怀疑这是故意的行为......?

1 个答案:

答案 0 :(得分:1)

首先:此代码根据[expr] / 4调用未定义的行为。因此,编译器可以推断出,因为在没有UB的情况下没有负值可以分配给b(编译器不会进一步考虑这种情况),b不能得到否定因此那个条件不需要检查。

如评论中所述,标记-fwrapv instructs the compiler to

  

[...]假设加法,减法和有符号算术溢出   乘法使用二进制补码表示。这个   flag启用一些优化并禁用其他优化。

有了它,GCC应该生成与低于O2的优化级别相同的程序。