2016-08-04 56 views
14

我正在用C++中的整数除法面临一些奇怪的结果。我试图计算:-2147483648/-1C++整数除法如何工作限制和负值?

我得到的是在3个不同的场景3个不同的结果:

int foo(int numerator, int denominator) { 
    int res = numerator/denominator; // produces SIGFPE, Arithmetic exception interrupt 

    cout << res << endl; 
} 

int main() { 
    int res = -2147483648/-1; 
    cout << res << endl;    // prints -2147483648 
    cout << -2147483648/-1 << endl; // prints 2147483648 
    foo(-2147483648, -1); 
    return 0; 
} 

为什么整数除法运算在不同情况下会产生不同的结果?

+1

值得一提的是,在VS-2015上,代码无法编译,称“负整数常量转换为无符号类型\t”,而“一元减运算符应用于无符号类型,结果仍为无符号”在所有'-2147483648/-1'行 –

+1

简单的答案[这里](http://stackoverflow.com/a/29355979/1460794)。 – wally

+2

这是visual studio如何做到这一点:'#define INT_MIN(-2147483647 - 1)//最小(有符号)整型值' – wally

回答

12

字面-2147483648/-1是由你的编译器中是足够宽以容纳该值的数据类型计算2147483648

当文字直接打印出来时,它会正确打印值。

当文字存储在res中时,它被转换为int。一个int在您的系统上似乎是32位宽。值2147483648不能表示为一个32位有符号整数,所以演员阵营会导致溢出。在你的系统上,这个溢出结果的值为-2147483648(可能是使用二进制补码)。

最后,试图在运行时执行除法(在foo功能)的情况下,SIGFPE异常发生由于溢出(因为int数据类型不能代表结果)。

注意,所有这三个选项的依靠平台的依赖行为:

  • 的事实,编译器不产生任何错误(或其他问题)字面计算溢出时,只是使用的数据类型大到足以容纳结果
  • 是存储字面当int溢出产生的事实,特定值(并没有其他问题)
  • 的事实SIGFPE异常被抛出在运行时
  • 溢出时
+0

AFAICT编译期间的整数溢出是Undefined Behavior;使用更大的数据类型是一种可能的行为,但FirstSTep显示,另一种行为是错误的。 – MSalters

+0

@ MSalters:是的,我在最后一段中陈述的很多。 –

+0

哪一个也是错误的:每个平台都必须支持足够宽的数据类型; 'long long int'肯定够宽。 – MSalters

12

您的结果可能是INT_MAX+1,换句话说可能会溢出。这是未定义的行为,任何事情都可能发生。例如,编译器可能会直接拒绝代码。

(A系统可能INT_MAX >= 2147483648,但你会期望你的3个测试用例相同的结果)

10
int res = -2147483648/-1; 
cout << res << endl;    // prints -2147483648 
cout << -2147483648/-1 << endl; // prints 2147483648 
int res = numerator/denominator; // produces SIGFPE, Arithmetic exception interrupt 

请注意,没有负面的integer literals

没有负整数文字。诸如-1之类的表达式将一元减运算符应用于文字表示的值,这可能涉及隐式类型转换。

字面2147483648大于int最大值大,所以它的类型将是long(或long long,取决于实现)。然后-2147483648的类型是long,并且计算结果(-2147483648/-1)也是long

对于第一情况下,结果2147483648long型的是implicitly convertedint,但它比的int最大值越大,结果是实现定义。 (看来结果根据代表(2的补数)这里的规则缠,让你得到的结果-2147483648

对于第二种情况,与long类型的结果直接打印出来,所以你得到正确的结果。

对于第3的情况下,你在做两个int S上的计算,结果可能不适合在结果类型(即int),signed integer arithmetic operation overflow发生的行为是不确定的。 (在此产生SIGFPE,算术异常中断)

+0

'-2147483648'可能是'long long',例如在MSVC(它有'LONG_MAX = 2147483647') – MSalters

+0

iirc在旧版本的C++中它可能也是一个32位无符号长(它实际上并没有改变最终结果,但它确实改变了你如何到达那里)。 – plugwash

+0

@plugwash我对“旧”C++不太了解。 :)现在,它将是'long'或'long long'(自C++ 11以来),除非使用后缀'u',否则它不会是'unsigned'。该表示是实现定义的,所以'long'可以用32位整数表示。 – songyuanyao