使用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 << 63
或1UL << 63
将unsigned 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位的平台,您应该没问题