【问题标题】:C++ integer overflowC++ 整数溢出
【发布时间】:2015-03-24 14:38:24
【问题描述】:

我刚刚开始自学 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

输出结果让我有点吃惊,我想知道是否有人可以解释为什么会发生这种情况,或者这些结果的意外性是否可以预料;所以这可能只是我的特定机器的结果。

【问题讨论】:

  • 这件事有什么让你吃惊的地方吗?你期待什么?
  • 我的期望是有符号和无符号的反应相似,它们都将变为 0。在阅读了 2 的赞美和 legends2k 的评论之后,它变得更有意义了。就带符号的 int 而言,我想我没想到最左边的位代表负号。
  • 如果它可以进一步提供帮助:这个 limits.h 为您提供每种本机类型的最大值和最小值的常量:cplusplus.com/reference/climits

标签: c++ integer-overflow


【解决方案1】:

有符号整数溢出是未定义的行为,而无符号整数溢出是明确定义的;价值环绕。换句话说,该值是模除以 2bits,其中 bits 是数据类型中的位数。因为你有一个 32 位的int

4294967295 + 1 = 4294967296 % 232 = 0

在第二种情况下它会导致 0。从语言的角度来看,第一种情况是未定义的。

但是,大多数实现都使用2's complement 来实现signed integer types。一个玩具,带符号的 4 位数据类型,使用 2 的补码实现,可用于解释第一种情况下发生的情况。在这种类型中

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并翻转位)

1000)2 - 1)2 = 0111)2

~0111)2 = 1000)2 = 8

因此最终值为-8。所有这一切都不是由语言定义的,但这就是你的情况,特别是。

【讨论】:

    【解决方案2】:

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

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

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

    如果将 1 加到 01111111111111111111111111111111,则得到 10000000000000000000000000000000,即十进制的 -2147483648。

    使用无符号整数,没有有符号位,而且事实上,可以有一个数字是最大有符号整数的两倍。但是,当号码再次滚动时(即11111111111111111111111111111111 + 00000000000000000000000000000001),您只需回滚到00000000000000000000000000000000

    如需更深入的了解,您可以查看two's complement,这是整数在计算机中的表示方式。

    【讨论】:

      【解决方案3】:

      整数有两种类型。有符号和无符号,传统上都是 32 位。

      在第一种情况下,您使用的是有符号整数。在这种情况下,1 位保留用于符号,其余 31 位用于幅度。在这种情况下,可以保存的最大数字是 2^31 - 1 = 2147483647。加一将影响最高有效位,将数字变为负数。 (Google 2 的数字补码表示法了解更多详情)。

      在第二种情况下,您使用的是 unsigned int,其中所有 32 位都保留用于幅度。因此,存储的最大数字是 2^32 - 1。向其中添加 1 将变为 0。 E.G. 假设我们有 3 位数字系统,111 = 7。加一将使其成为 1000,但由于它是 3 位系统,它将变为 000 = 0

      【讨论】:

        【解决方案4】:

        阅读二进制补码。基本上,一旦你达到你的处理器可以支持的最高整数并且你给它加 1,它就会通过打开“符号”位变成负数。

        【讨论】:

        • 你没有翻转计数器。最大有符号 8 位数字是 01111111,当您添加 1 时,它变为 10000000,并且取决于您的机器如何解释负数(只是一个有符号位、1s 恭维、2s 恭维),该数字将被解释为某个负数。当你说“翻转”柜台时,我明白你在说什么,但我认为这种措辞令人困惑和误导
        猜你喜欢
        • 2020-10-22
        • 1970-01-01
        • 2022-01-07
        • 2013-04-10
        • 2022-01-21
        • 2021-03-15
        • 1970-01-01
        相关资源
        最近更新 更多