unsigned long无法正确存储超2147483647数值,求解原因
为什么
unsigned long赋值0x80 << 24会得到错误结果? 先看你的代码和实际输出:
#include <iostream> using namespace std; int main() { unsigned long P; P = 0x7F << 24; cout << P << endl; P = 0x80 << 24; cout << P << endl; return 0; }
输出结果:
2130706432 18446744071562067968
问题核心出在整数常量的默认类型和移位操作的类型规则上,我给你拆解清楚:
- 首先,
0x80是C++默认的有符号int类型常量(多数系统中int为4字节32位)。当执行0x80 << 24时,移位操作是在int类型下进行的:0x80的二进制是00000000 00000000 00000000 10000000,左移24位后变成10000000 00000000 00000000 00000000——这个值超出了32位有符号int的最大值(0x7FFFFFFF,即2147483647),属于有符号整数溢出,此时这个值在有符号语境下是负数(最高位为符号位)。
- 当把这个溢出的有符号int赋值给
unsigned long变量P时,C++会触发符号扩展:因为原int是负数,转换为无符号类型时会把所有高位填充1。如果你的系统中unsigned long是8字节64位,那么32位的负数0x80000000会被扩展成0xFFFFFFFF80000000,转换成十进制就是你看到的18446744071562067968。
而0x7F <<24能得到正确结果,是因为0x7F左移24位后是0x7F000000,这个值在32位有符号int的范围内(小于0x7FFFFFFF),是正数,转换为unsigned long时只会高位补0,所以结果符合预期。
修复方案
只需要把常量标记为无符号类型,让移位操作在无符号语境下执行:
P = 0x80UL << 24; // 用UL后缀将常量指定为unsigned long类型
这样0x80UL是unsigned long类型,左移24位后得到0x80000000,转换成十进制就是你预期的2147483648。
内容的提问来源于stack exchange,提问作者Akira Tsuchiya
相关产品推荐
相关产品推荐

