C++整型溢出

6
我是一名有用的助手,可以为您翻译文本。

我刚开始自学C++,并开始学习整数溢出。出于好奇,我编写了一些测试来查看特定整数值的情况。

这是我的程序:

#include <iostream>

int main()
{
    int x(0);
    std::cout << x << std::endl;

    x = x + 2147483647;
    std::cout << x << std::endl;

    x = x + 1;
    std::cout << x << std::endl;
    std::cout << std::endl;

    unsigned int y(0);
    std::cout << y << std::endl;

    y = y + 4294967295;
    std::cout << y << std::endl;

    y = y + 1;
    std::cout << y << std::endl;
}

以下是输出结果:

0
2147483647
-2147483648

0
4294967295
0

输出结果让我有些惊讶,我在想是否有人能解释一下为什么会出现这种情况,或者说这些结果的意外性是预料之中的;所以这可能只是由于我的特定机器造成的。


5
你对这件事有什么惊讶之处?你期待发生什么? - Borgleader
我的期望是signed和unsigned都会有类似的反应,它们都会变成0。在阅读了2的补码和legends2k的评论后,这使我更加明白了。就signed int而言,我想我没有预料到最左边的位代表负号。 - Zack Downs
4个回答

9
有符号整数溢出是未定义的行为,而无符号整数溢出是被明确定义的,值会被环绕。换句话说,该值会模除2的次幂,其中是数据类型中的位数。由于您有一个32位的int

4294967295 + 1 = 4294967296 % 232 = 0

在第二种情况下结果为0。从语言角度来看,第一种情况是未定义的。
然而,大多数实现使用二进制补码来实现有符号整数类型。可以使用使用二进制补码实现的玩具型有符号4位数据类型来解释第一种情况。在此类型中,

POS_MAX = 7 = 0111)2

NEG_MAX = -8 = 1000)2

该类型可以容纳24 = 16个状态,8个正数(0到7)和8个负数(-1到-8)。

POS_MAX + 1 = 0111)2 + 1)2 = 1000)2

由于第一个位被设置为1,它是一个负数,要找到实际值,请执行两个补码的反向操作(减去1并翻转位)

1000)2 - 1)2 = 0111)2

~0111)2 = 1000)2 = 8

因此最终值为-8。所有这些都不是由语言定义的,但这就是在您的情况下发生的事情。


7

整数(通常情况下)采用32位表示。如果您有32位,您可以从0到231-1寻址。即:

00000000000000000000000000000000
00000000000000000000000000000001
.
.
.
01111111111111111111111111111111
^-------------------------------
signed bit

0表示正数,1表示负数。

如果你将01111111111111111111111111111111加1,则得到10000000000000000000000000000000,在十进制中表示为-2147483648。

使用无符号整数时,没有符号位,因此可以拥有的数字是有符号整数最大值的两倍。但是,当数字再次翻转(即11111111111111111111111111111111+00000000000000000000000000000001)时,您只需回滚到00000000000000000000000000000000

要深入了解,请查看二进制补码,这是计算机中整数的表示方式。


1
整数有两种类型:有符号和无符号,传统上都是32位。
在第一种情况下,您使用的是有符号整数。在这种情况下,1个比特用于符号,其余31个用于大小。在这种情况下,可以保存的最大数字为2^31 - 1 = 2147483647。将其加一会影响最高有效位,将数字更改为负数。(有关更多详细信息,请搜索二进制补码表示法)。
在第二种情况下,您使用的是无符号整数,其中所有32位都用于大小。因此,可以存储的最大数字为2^32 - 1。将其加一会变成零。例如,假设我们有一个3位数字系统,111=7。将其加一会变成1000,但由于它是3位系统,所以它会变成000=0。

-1

了解一下二进制补码。基本上,一旦你达到处理器支持的最大整数并将其加1,它会通过打开“符号”位进入负数。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接