为什么我不能在 64 位机器上将 2^64 存储在 unsigned long 中?

Why can't I store 2^64 in an unsigned long on a 64-bit machine?

我错过了什么吗?我有 运行 以下内容:

$ uname -a
Linux archlinux 4.16.6-1-ARCH #1 SMP PREEMPT Mon Apr 30 12:30:03 UTC 2018 x86_64 GNU/Linux

然后在C程序中:

long l;
printf("sizeof long: %d\n", sizeof l);

哪个输出:

sizeof long: 8

这不是说每个long包含64位吗? 但是当我执行以下代码行时:

printf("2^64: %ld\n",  1UL<<64);

我从 gcc 收到以下警告:

sizeof.c:14:29: warning: left shift count >= width of type [-Wshift-count-overflow]

如果我改为将左移位减少到 63,则警告消失,但它输出:

2^64: -9223372036854775808

这让我相信我假设 unsigned long 是 64 位可用位是不正确的,但为什么呢?

数字 2^64 需要 65 位才能正确表示二进制 - 第 65 位已设置,其余为零。

这与无符号 8 位数字最多只能达到 255 (2^8 - 1),无符号 16 位数字最多只能达到 65535 (2^16 - 1),以及依此类推

sizeof 确实会 return 你的字节数,所以是的,它确实有 64 位。 使用 N 个二进制数字,您可以表示总共 2^N 个数字。如果你的变量是无符号的,这意味着 [0, (2^N)-1] 范围。如果它是一个带符号的数字,那么范围应该是 [-2^(N-1), +2^(N-1)-1]。如果您想了解有关带符号整数的更多信息,可以阅读 "Two's complement"。

继续显示您的整数:您告诉 printf 如何解释变量。如果你告诉它是一个带符号的整数,那么它将使用最高有效位作为符号而不是值 2^63(再次检查 Two's complement)。

另一方面,这将打印无符号整数:

printf("%lu", x);