以下C ++代码片段计算Fibonacci数字。对于32位整数,当n=47
和b
变为负数时,我们会溢出。
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
。编译器是否可能假设,a
和b
开始为正且仅应用了添加,它们必须保持正数?查看装配输出确认条件b>0
即使被检查也是如此。
g ++ 4.7.0也是如此。所以我怀疑这是故意的行为......?
答案 0 :(得分:1)
首先:此代码根据[expr] / 4调用未定义的行为。因此,编译器可以推断出,因为在没有UB的情况下没有负值可以分配给b
(编译器不会进一步考虑这种情况),b
不能得到否定因此那个条件不需要检查。
如评论中所述,标记-fwrapv
instructs the compiler to
[...]假设加法,减法和有符号算术溢出 乘法使用二进制补码表示。这个 flag启用一些优化并禁用其他优化。
有了它,GCC应该生成与低于O2的优化级别相同的程序。