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

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

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

1 << 63将在int算术中计算,你的int可能是32位。

通过推广其中一个论点来解决这个问题: 1ULL << 63会做到这一点。

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

表达式1 << 63类型为int 。 在大多数系统中, int的范围是-2 31 ... 2 31 - 1,2 63对于那个来说太大了。 尝试使用(unsigned long)1 << 63 1UL << 63 (unsigned long)1 << 631UL << 63unsigned long整数类型的值移位63位。

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

 1ULL << 63 

这里的1称为整数常量 。 根据标准中规定的规范, C11 ,章节§6.4.4.1的语法相同

整型常量:
十进制常数整数后缀opt
八进制常数整数后缀opt
hex常量整数后缀opt

关于语义学,

整数常量的类型是相应列表中可以表示其值的第一个。

并且该表说,如果没有后缀,并且该值可以在int范围内表示,则应将其视为int 。 所以,这里的1被认为是一个int通常是 4个字节,或32位,在你的情况下也是一样的。

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

 1UL << 63 

应该解决你的问题。

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