我的问题分为三个部分
问题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;
}
未使用特定的编译器优化选项或使用O标志。它是基本的编译命令g ++ -o test main.cpp用于形成可执行文件。
看似非常简单的代码,在SUSE 64位操作系统,gcc版本4.1.2中有奇怪的行为。预期输出为“Number is negative”,而不是仅在SUSE 64位OS中,输出为“Number is positive”。
经过一些分析并对代码进行“解除”后,我发现编译器以下面的格式进行优化 -
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
假设我有一个巨大的代码库,我迁移了我的编译器版本,这样的bug /优化可能会对我的系统行为造成严重破坏。从业务角度来看,仅仅因为编译器升级而再次测试所有代码行是非常无效的。
我认为,出于所有实际目的,这些错误很难被捕获(在升级过程中),并且总是会泄漏到生产现场。
有人可以建议任何可能的方法来确保这些错误/优化对我现有的系统/代码库没有任何影响吗?
PS:
更新(1)
我想要实现什么?变量我将是一个计数器(一种syncID)。如果我执行离线操作(50操作)然后在启动期间,我想重置我的计数器,为此我检查边界值(重置它)而不是盲目地添加它。
我不确定我是否依赖于硬件实现。我知道0X7FFFFFFF是最大正值。我所做的就是,通过增加价值,我期待返回值为负值。我不认为这个逻辑与硬件实现有任何关系。
无论如何,非常感谢您的意见。
更新(2)
大多数inpit声明我依赖于溢出检查的较低级别行为。我对此有一个问题,
除非我检查数字的否定性,否则我无法做到这一点。所以我的主张是,当一个值加到+ MAX_INT时,int必须返回一个负数。
请告诉我您的意见。
答案 0 :(得分:11)
这是一个已知问题,我不认为它被认为是编译器中的错误。当我使用gcc 4.5与-Wall -O2
进行编译时,它会发出警告
警告:假设假设(X + c)&lt; X总是假的
虽然您的代码 溢出。
您可以传递-fno-strict-overflow
标志以关闭该特定优化。
答案 1 :(得分:3)
您的代码会产生未定义的行为。 C和C ++语言没有用于有符号整数运算的“溢出机制”。您的计算溢出了有符号整数 - 行为立即未定义。考虑到它形成“编译器中的错误与否”,尝试分析i = i++ + ++i
示例时没有什么不同。
GCC编译器具有基于C / C ++语言规范部分的优化。它被称为“严格溢出语义”或湖泊。它基于以下事实:在C ++中向有符号整数添加正值总是产生更大的值或导致未定义的行为。这立即意味着编译器可以完全自由地假设总和总是更大。该优化的一般性质与GCC中也存在的“严格别名”优化非常相似。他们都引起了海湾合作委员会用户社区中更“黑客”部分的一些抱怨,其中许多人甚至不怀疑他们在C / C ++程序中依赖的技巧只是非法黑客攻击。
答案 2 :(得分:2)
Q1:也许,64位实现中的数字确实是正数?谁知道?在调试代码之前,我只需要printf(“%d”,i + v);
Q2:括号只是告诉编译器如何解析表达式。这通常以树的形式完成,因此优化器根本看不到任何括号。并且可以自由地转换表达式。
问题3:这就是为什么,作为c / c ++程序员,你不能编写承担底层硬件特定属性的代码,例如,int是32位数量的二进制补码形式。
答案 3 :(得分:0)
该行:
cout<<(i + v)<<endl;
SUSE示例中的输出?你确定你没有64位整数?
答案 4 :(得分:0)
使用gcc 4.1.2指定的OP没有任何特殊标志。我假设缺少-O
标志等同于-O0
。在没有请求优化的情况下,为什么gcc会以报告的方式优化代码?在我看来,这似乎是一个编译器错误。我还假设在以后的版本中已经修复了这个问题(例如,一个答案提到了gcc 4.5和-fno-strict-overflow
优化标志)。当前的gcc手册页指出-fstrict-overflow
包含-O2
或更多。
在当前版本的gcc中,有一个选项-fwrapv
,可以让您使用导致OP出现问题的代码。当然,您必须确保知道整数类型的位大小。来自gcc手册页:
-fstrict-overflow ..... See also the -fwrapv option. Using -fwrapv means that integer signed overflow is fully defined: it wraps. ... With -fwrapv certain types of overflow are permitted. For example, if the compiler gets an overflow when doing arithmetic on constants, the overflowed value can still be used with -fwrapv, but not otherwise.