You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何64位机器上unsigned long无法存储2^64?

问题解析:unsigned long 左移的那些坑

先给你拆解下你遇到的几个核心问题:

1. 为什么 1UL << 64 会触发警告?

C语言标准明确规定:对于任何整数类型,左移的位数必须严格小于该类型的位宽度。哪怕是无符号类型也不例外——当左移位数等于或超过类型的位宽度时,行为是未定义的(Undefined Behavior)。

你的系统里unsigned long是64位(因为long是8字节=64位,unsigned long和long位宽相同),所以最大的合法左移位数是63(从0开始计数的话,第63位是最高位)。1UL << 64违反了这个规则,gcc自然会抛出shift-count-overflow警告。

2. 为什么 1UL << 63 用%ld输出会得到负数?

这里的问题出在格式符不匹配:

  • 1UL是unsigned long类型,左移63位后的值是2^63,这是unsigned long能表示的最大值的一半(64位无符号数范围是0到2^64-1)。
  • 但你用了%ld格式符,这个格式符是用来输出有符号long类型的。当把unsigned long的2^63传给printf时,它会被当作有符号long来解析:在补码表示中,64位有符号long的最高位是符号位,2^63对应的二进制是最高位为1、其余为0,这正好是有符号long能表示的最小负数:-9223372036854775808。

如果要正确输出unsigned long类型的值,你应该用%lu格式符,试试这个:

printf("2^63 (unsigned): %lu\n", 1UL << 63);

这样输出就会是正确的9223372036854775808。

3. 关于unsigned long的位宽验证

你通过sizeof(long)得到8字节,确实说明long是64位,unsigned long自然也是64位(无符号版本只是改变了符号位的解读,位宽和对应的有符号类型一致)。你之前的疑惑只是因为位运算规则和格式符匹配的问题,并不是unsigned long的位宽不对。

总结一下:

  • 左移位数不能等于或超过类型的位宽度,否则是未定义行为
  • 输出无符号类型时一定要用对应的无符号格式符(%lu对应unsigned long,%u对应unsigned int等)

内容的提问来源于stack exchange,提问作者papiro

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 04:07:26