C++中的整数上溢和下溢

Integer overflow and underflow in C++

谁能解释一下为什么会这样?? :

int a = 2147483647;
cout <<"Product = " << a * a << endl; // output = 1 (why?)
int b = -2147483648;
cout <<"Product = " << b * b << endl; // output = 0 (why?)

另外,当我们为 'short' 编写类似的代码时,尽管变量被初始化为 short 类型,编译器仍将乘积视为整数类型,例如:

short x = 32767;
cout <<"Product = " << x * x << endl; // Product = 1073676289
short y = -32768;
cout <<"Product = " << y * y << endl;// Product = 1073741824

第 1 部分:直觉,无需参考资料

让我们尝试使用一些直觉或合理假设来解释为什么这些结果有意义。

基本上,这是关于物理整数变量可以表示的内容 - 这不是所有整数的整个无限集,而是范围 -2^31 ... 2^31 - 1(对于 32-位整数,这可能是你所拥有的;但请务必检查以确保,例如使用 sizeof().)

现在,如果

a = 2^31 - 1

然后

a*a = (2^31 - 1)^2 = 2^62 - 2*2^31 + 1 = 2^62 - 2^32 + 1

作为理想整数,忽略物理表示。当将结果放置为 32 位整数时,合理的猜测是 CPU 给你的任何结果都将等同于理想结果的模 2^31 或 2^32:

  (2^62 - 2^32 + 1) mod 2^32
= (2^62 mod 2^32) - (2^32 mod 2^32) + (1 mod 2^32) 
= 1 mod 2^32

这就是你得到的。

对于 b,您有:

b = -2147483648 = -2^31

b*b = 2^62

等于 0,模 2^31 或 2^32。


第 2 部分:语言的要求

虽然我们的直觉确实对结果给出了合理的解释,但考虑“官方”答案通常也很有用。在我们的例子中,我引用了 cppreference.com(这不是官方语言标准,但足够接近):

When signed integer arithmetic operation overflows (the result does not fit in the result type), the behavior is undefined: it may wrap around according to the rules of the representation (typically 2's complement), it may trap on some platforms or due to compiler options (e.g. -ftrapv in GCC and Clang), or may be completely optimized out by the compiler.

所以实际上,你不能保证在不同的编译器、不同的编译器版本、不同的机器甚至重复编译相同的代码时得到这些值!你实际上可以得到 1234 和 5678 作为结果,你不能抱怨。或者你的程序可能会崩溃。或者其他任何事情都可能发生!参见:

Undefined, unspecified and implementation-defined behavior

关于你问题的第二部分(关于 shorts)- 这是由于 integer promotion:

The arguments of the following arithmetic operators undergo implicit conversions for the purpose of obtaining the common real type, which is the type in which the calculation is performed:

  • binary arithmetic *, /, %, +, -

...

Integer promotion is the implicit conversion of a value of any integer type with rank less or equal to rank of int or of a bit field of type ...short [other types here] to the value of type int or unsigned int

第 3 部分:实用底线

注意避免计算值超过 std::numeric_limits<T>::max():使用较大的类型开始,或检查过高的值(例如,确保两个值的绝对值都低于 2^16,否则应用一些特殊处理)。

Can anyone please explain why this happens ?? :

int a = 2147483647;
cout <<"Product = " << a * a << endl; // output = 1 (why?)

因为程序的行为是未定义的。

int b = -2147483648;
cout <<"Product = " << b * b << endl; // output = 0 (why?)

因为程序的行为是未定义的。

Also when we write the similar for 'short' , the compiler takes the product as integer type despite the variables being initialized as of short type, like:

整数算术运算中所有低于int的操作数都隐式转换为int(如果它可以表示源类型的所有值;否则转换为unsigned int).这种转换称为整数提升。