gcc优化?错误?以及它对项目的实际意义

kum*_*ran 11 c++ optimization gcc

我的问题分为三个部分

问题1
考虑以下代码,

#include <iostream>
using namespace std;

int main( int argc, char *argv[])
{

    const int v = 50;
    int i = 0X7FFFFFFF;

    cout<<(i + v)<<endl;

    if ( i + v < i )
    {
        cout<<"Number is negative"<<endl;
    }
    else
    {
        cout<<"Number is positive"<<endl;
    }

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

没有使用特定的编译器优化选项或使用O标志.它是基本的编译命令g ++ -o test main.cpp用于构成可执行文件.

看似非常简单的代码,在SUSE 64位操作系统,gcc版本4.1.2中有奇怪的行为.预期输出为"Number is negative",而仅在SUSE 64位OS中,输出为"Number is positive".

经过一些分析并对代码进行"解除"后,我发现编译器以下面的格式进行优化 -

  • 由于i在比较的两边是相同的,所以不能在同一表达式中更改,从等式中删除"i".
  • 现在,比较导致if ( v < 0 ),其中v是常数正数,因此在编译期间,else部分cout函数地址被添加到寄存器中.没有找到cmp/jmp指令.

我看到行为仅在gcc 4.1.2 SUSE 10中.在AIX 5.1/5.3和HP IA64中尝试时,结果如预期.

以上优化是否有效?
或者,使用int的溢出机制不是一个有效的用例?

问题2
现在,当我将条件语句更改if (i + v < i)if ( (i + v) < i )偶数时,行为是相同的,至少我个人不同意,因为提供了额外的大括号,我希望编译器创建一个临时的内置类型变量并进行比较,从而使优化无效.

问题3
假设我有一个庞大的代码库,我迁移了我的编译器版本,这样的错误/优化可能会对我的系统行为造成严重破坏.从业务角度来看,仅仅因为编译器升级而再次测试所有代码行是非常无效的.

我认为,出于所有实际目的,这些类型的错误很难捕获(在升级过程中)并且总是会泄漏到生产现场.

任何人都可以建议任何可能的方法来确保这些错误/优化对我现有的系统/代码库没有任何影响吗?


PS:

  • 当从代码中删除const for v时,编译器不会进行优化.
  • 我相信,使用溢出机制来查找变量是否来自MAX - 50值(在我的情况下)是完全没问题的.

更新(1)
我想要实现什么?变量我将是一个计数器(一种syncID).如果我执行离线操作(50操作)然后在启动期间,我想重置我的计数器,为此我检查边界值(重置它)而不是盲目地添加它.

我不确定我是否依赖于硬件实现.我知道0X7FFFFFFF是最大正值.我所做的就是,通过增加价值,我期待返回值为负值.我不认为这个逻辑与硬件实现有任何关系.

无论如何,谢谢你的意见.


更新(2)
大多数inpit声明我依赖于溢出检查的低级行为.我有一个相同的问题,

  • 如果是这种情况,对于unsigned int,如何在下溢或溢出期间验证和重置值?如果v = 10,i = 0X7FFFFFFE,我想重置i = 9.同样对于下溢?

除非我检查数字的否定性,否则我无法做到这一点.所以我的主张是,当一个值加到+ MAX_INT时,int必须返回一个负数.

请让我知道您的意见.

ken*_*ytm 11

这是一个已知问题,我不认为它被认为是编译器中的错误.当我使用gcc 4.5进行编译时-Wall -O2会发出警告

警告:假设假设(X + c)<X始终为假,则不会发生签名溢出

虽然你的代码确实溢出了.

您可以传递该-fno-strict-overflow标志以关闭该特定优化.

  • +1.需要强调的是,GCC的行为是符合标准的,因为标准说这种操作中的溢出会导致不确定的行为. (8认同)