为什么 UINT32_MAX + 1 = 0?

Lar*_*sen 4 c++

考虑以下代码片段:

#include <cstdint>
#include <limits>
#include <iostream>

int main(void) 
{
    uint64_t a = UINT32_MAX;
    std::cout << "a: " << a << std::endl;
    ++a;
    std::cout << "a: " << a << std::endl;
    uint64_t b = (UINT32_MAX) + 1;
    std::cout << "b: " << b << std::endl;

    uint64_t c = std::numeric_limits<uint32_t>::max();

    std::cout << "c: " << c << std::endl;

    uint64_t d = std::numeric_limits<uint32_t>::max() + 1; 
    std::cout << "d: " << d << std::endl;
    return 0; 
}
Run Code Online (Sandbox Code Playgroud)

这给出了以下输出:

#include <cstdint>
#include <limits>
#include <iostream>

int main(void) 
{
    uint64_t a = UINT32_MAX;
    std::cout << "a: " << a << std::endl;
    ++a;
    std::cout << "a: " << a << std::endl;
    uint64_t b = (UINT32_MAX) + 1;
    std::cout << "b: " << b << std::endl;

    uint64_t c = std::numeric_limits<uint32_t>::max();

    std::cout << "c: " << c << std::endl;

    uint64_t d = std::numeric_limits<uint32_t>::max() + 1; 
    std::cout << "d: " << d << std::endl;
    return 0; 
}
Run Code Online (Sandbox Code Playgroud)

为什么是bd两者0?我似乎找不到对此的解释。

Ama*_*l K 5

这种行为称为溢出。uint32_t占用 4 字节或 32 位内存。当您使用时,UINT32_MAX您将 32 位中的每一个都设置为 1,这是 4 字节内存可以表示的最大值。1是一个整数文字,通常也占用 4 个字节的内存。因此,您基本上是在 4 个字节可以表示的最大值上加 1。这是最大值在内存中的样子:

1111 1111 1111 1111 1111 1111 1111 1111
Run Code Online (Sandbox Code Playgroud)

当您为此添加 1 时,没有更多空间来表示大于最大值的 1,因此所有位都设置为 0 并返回到它们的最小值。尽管您要分配给uint64_t容量为 两倍的uint32_t,但它仅在加法操作完成后才分配。加法运算检查左右操作数的类型,这决定了结果的类型。如果至少一个值是 type uint64_t,则另一个操作数也会自动提升uint64_t。如果你这样做:

 (UINT32_MAX) + (uint64_t)1;
Run Code Online (Sandbox Code Playgroud)

或者:

 (unint64_t)(UINT32_MAX) + 1;
Run Code Online (Sandbox Code Playgroud)

,你会得到你所期望的。在像 C# 这样的语言中,您可以使用checked块来检查溢出并防止这种情况发生。

  • 在标准中它不被称为溢出。它的行为定义明确,无符号算术被定义为模算术 (3认同)
  • 另外,值得注意的是,即使两个操作数都是 `uint8_t` 或 `uint16_t`,例如:`(UINT8_MAX + (uint8_t)1)` 或 `(UINT16_MAX + (uint16_t)1)` ,结果仍然是提升为“int”。对小于“int”的数字类型的任何操作都会将结果提升为“int”。 (2认同)