此操作的 unsigned long int 是否正确?

Is unsigned long int correct for this operation?

这是我的代码:

#include <stdio.h>

int main(int argc, char *argv[]) {

    unsigned long int x = 0;

    // trying to make x = 2,147,483,648
    x = 1 << 31;

    printf("%lu", x);
}

它返回 x = 18446744071562067968。我读到 unsigned long int 应该达到 4,294,967,296,那么为什么我不能使用 1 << 32 来设置 x 等于 2,147,483,648?

如果您的系统有 32 位整数,

1 << 31 会导致未定义的行为。文字 1 是一个带符号的整数。

您需要进行无符号班次而不是有符号班次:

x = 1UL << 31;

我添加了L,这样代码即使在16位系统上仍然是正确的,这样做也无妨。


非正式地,将 1 移入符号位是未定义的。正式文本可以在C11标准的6.5.7/4部分找到:

The result of E1 << E2 is E1 left-shifted E2 bit positions; vacated bits are filled with zeros. [...] If E1 has a signed type and nonnegative value, and E1 × 2E2 is representable in the result type, then that is the resulting value; otherwise, the behavior is undefined.


你的另一个问题 "why can't I use 1 << 32" 也包含在同一句话中。 1UL << 32 呢?如果您的系统有 32 位 unsigned long 那么根据 6.5.7/3 这也是未定义的:

[...] If the value of the right operand is negative or is greater than or equal to the width of the promoted left operand, the behavior is undefined

但如果您的系统是 64 位 unsigned long,它就可以工作。为避免在不同系统上编译时代码中断(此目标称为 代码可移植性),您可以编写 (uint64_t)1 << 32(或 1ULL << 32),这是有保证的上班。