为什么“INT_MAX * INT_MAX”乘积给出 1?

Sid*_*oor 2 c integer-overflow cpu-architecture

我正在学习计算机体系结构,并决定尝试乘法溢出。观察到 的溢出INT_MAX * INT_MAX,但我不确定为什么这会在 C/C++ 中给出乘积 1。

#include <stdio.h>
#include <limits.h>

int main()
{
    int num = INT_MAX;
    printf("%0x\n", num);       //stdout is 0x7fffffff
    printf("%d\n", num * num);  //stdout is 1
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

Kam*_*Cuk 6

注意:您的代码无效。溢出int*int未定义的行为,您不应该编写此类代码。结果将是不可预测的。这是一个玩具示例,其中编译器选择以特定方式执行操作 - 但通常,编译器可以对您的代码执行任何操作。如果您希望定义有符号溢出,请参阅示例,当使用 -fwrapv 时,有符号溢出在 gcc 中仍然是未定义的行为吗?


例如,假设int您的平台有 32 位并且是二进制补码。计算结果,然后截断为 32 位。

INT_MAX = 0x7fffffff = 2147483647
2147483647 * 2147483647 = 4611686014132420609
4611686014132420609     = 0x3fffffff00000001
32-bits from 0x3fffffff00000001 = 0x00000001 = 1
Run Code Online (Sandbox Code Playgroud)

  • 令人震惊的是,人们写下“结果将是不可预测的”,而实际上结果是可以预测的。 (4认同)
  • @EricPostpischil 它是在一个特定的实现中。如果您使用不同的编译器进行编译或针对其他硬件,情况可能会有所不同。 (2认同)
  • @Ranoiaetep:“标准不保证”与“不可预测”是不同的。 (2认同)
  • @EricPostpischil IMO 吹毛求疵。只是使用了错误的措辞。大多数 UB 结果可以在假设特定实施的情况下进行预测。 (2认同)
  • @EricPostpischil:这是“可以解释的”,但我不会在“预测”上花太多钱来预测该代码在不尝试的情况下会打印什么,即使我知道它将由像 GCC 这样的特定编译器进行编译。我真的没想到 GCC 在不使用“-fwrapv”进行编译时将“INT_MAX * INT_MAX”视为“__builtin_unreachable()”以使其定义明确,但它当然可以。显然任何其他编译器都可以做出不同的选择。`gcc -fsanitize=undefined` 也是一个符合标准的 C 实现.. 尽管它在打印错误后确实打印了 `1`。 (2认同)