这是我的代码:
#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&lt;&lt; 32设置x等于2,147,483,648?
答案 0 :(得分:3)
1 << 31
会导致未定义的行为。文字1
是一个有符号的int。
您需要执行无符号移位而不是签名移位:
x = 1UL << 31;
我添加了L
,这样即使在16位系统上代码仍然正确,这样做并没有什么坏处。
非正式地,将1
转换为符号位是未定义的。正式文本见C11标准第6.5.7 / 4节:
E1 << E2
的结果是E1
左移E2
位位置;腾出的位用零填充。 [...]如果E1
具有签名类型和非负值,并且E1
×2
E2
在结果类型中可表示,那就是结果价值;否则,行为未定义。
你的另一个问题,“为什么我不能使用1 << 32
”被同一个引用所涵盖。那么1UL << 32
呢?如果您的系统具有32位unsigned long
,则根据6.5.7 / 3,这也将是未定义的:
[...]如果右操作数的值为负或大于或等于提升的左操作数的宽度,则行为未定义
但如果您的系统具有64位unsigned long
,它将起作用。为避免在其他系统上编译时代码中断(此目标称为代码可移植性),您可以编写(uint64_t)1 << 32
(或1ULL << 32
),这可以保证正常工作。