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

时间:2016-01-31 20:32:57

标签: c long-integer bit-shift

这是我的代码:

#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?

1 个答案:

答案 0 :(得分:3)

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

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),这可以保证正常工作。