使用 unsigned long 类型进行位移会产生错误的结果

bit shifting with unsigned long type produces wrong results

我有点困惑,因为我想在我的系统(我想是每个现代系统)上初始化一个大小为 8 字节的 unsigned long 类型的变量。当我想将 1 << 63 分配给变量时,我收到了编译器警告,并且该数字实际上是 0。当我执行 1 << 30 时,我得到了 2 ^ 30 = 1073741824 的预期结果。然而,当我执行 1 << 31 时,我得到 2 ^ 64 的结果(我认为;实际上这不应该是可能的)打印 18446744071562067968

任何人都可以向我解释这种行为吗?

1 << 63 将在 int 算法中计算,而您的 int 可能是 32 位。

通过提升其中一个参数来解决这个问题:1ULL << 63 会做到。

ULL 表示表达式至少为 64 位。

表达式 1 << 63 的类型为 intint 的范围是 -231 … 231 - 在大多数系统上是 1,263 太大了。尝试 (unsigned long)1 << 631UL << 63 将类型 unsigned long 的值左移 63 位。

这里的1,叫做整数常量。根据标准 C11 中指定的规范,第 §6.4.4.1 章的语法是

integer-constant:
     decimal-constant integer-suffixopt
     octal-constant integer-suffixopt
      hexadecimal-constant integer-suffixopt

关于语义,

The type of an integer constant is the first of the corresponding list in which its value can be represented.

和 table 表示,如果没有后缀,并且值在 int 范围内代表 table,则应将其视为 int。因此,这里的 1 被认为是 int,通常 4 个字节,或 32 位,在您的情况下也是如此。

要明确指定 1unsigned long (64) 位,我们可以使用后缀,例如

1UL << 63

应该可以解决您的问题。

请注意:unsigned long 不保证为 64 位。 unsigned long long保证至少有64位。但是,只要您使用 unsigned long 是 64 位的平台,您应该没问题

我建议您使用 1ULL,因为这将为您提供 32 位和 64 位架构上的 64 位无符号整数。 在 32 位架构上 unsigned long(因此 UL)只有 32 位长,无法解决问题。

1ULL << 63