为什么 -0x80000000 + -0x80000000 == 0?

Why does -0x80000000 + -0x80000000 == 0?

在阅读一本关于编程技巧的书时,我看到 -0x80000000 + -0x80000000 = 0。这对我来说没有意义,所以我在下面写了一个快速的 C 程序来测试,答案确实是 0:

#include <stdio.h>

int main()
{
    int x = -0x80000000;
    int y = -0x80000000;

    int z = x + y;

    printf("Z is: %d", z);
    return 0;
}

谁能解释一下为什么?我看到了一些关于溢出的信息,但我看不出溢出是如何导致 0 而不是异常或其他错误的。我没有收到任何警告或任何信息。

这里发生的是有符号整数溢出,这是 undefined behavior 因为没有定义有符号整数的确切表示。

然而实际上,大多数机器使用 2 的补码表示有符号整数,而这个特定程序利用了它。

0x80000000 是无符号整型常量。 - 否定它,将表达式更改为有符号。假设 int 在您的系统上是 32 位的,这个值仍然适合。事实上,它是一个带符号的32位int所能容纳的最小值,而这个数的十六进制表示恰好是0x80000000.

在用2的补码表示加法时,具有不用担心符号的特点。它们的添加方式与无符号数完全相同。

所以当我们添加 xy 时,我们得到:

   0x80000000
+  0x80000000
-------------
  0x100000000

因为您系统上的 int 是 32 位的,所以只保留最低的 32 位。这些位的值为 0.

再次注意,这实际上是未定义的行为。它之所以有效,是因为您的机器对有符号整数使用 2 的补码表示,而 int 是 32 位。这对大多数机器/编译器都很常见,但不是全部。

您看到的是很多实现定义的行为,很可能在运行时触发未定义的行为。如果没有关于您和本书作者架构的详细信息,就不可能知道更多。

没有附加信息,结果没有意义。如果你想要一个明确的答案,请查阅你的体系结构的类型范围,并确保赋值和算术的结果适合它们各自的类型。