为什么我不能在 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);
我错过了什么吗?我有 运行 以下内容:
$ 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);