C++(5):有符号整数和无符号整数差异
一、代码实例与现象
#include <iostream>
using namespace std;int main()
{short int i; // 有符号短整数(16位)short unsigned int j; // 无符号短整数(16位)j = 50000; // 合法赋值(无符号范围:0~65535)i = j; // 将无符号值赋给有符号变量cout << i << " " << j; // 输出:-15536 50000return 0;
}
二、现象分析
1. 数值范围差异
类型 | 范围(16位) |
---|---|
short int (有符号) | -32768 到 32767 |
unsigned short (无符号) | 0 到 65535 |
-
j = 50000
在无符号范围内合法。 -
i = j
时,50000 超出有符号短整数的最大值(32767),导致溢出。
2. 二进制位模式解释
-
无符号数
j
的二进制:
50000
的二进制为1100001101010000
(直接按正数解析)。 -
有符号数
i
的二进制:
相同二进制1100001101010000
被解释为负数(最高位为符号位)。
补码计算:-(~1100001101010000 + 1) = -15536
。
三、底层原理--补码机制
-
有符号数的存储:
-
最高位为符号位(0正1负)。
-
负数以补码形式存储(取反后加1)。
-
-
转换过程:
-
无符号数
50000
的二进制直接复制到有符号变量。 -
有符号变量按补码规则解析该二进制,得到负数。
-
四、对比实例:合法范围赋值
short int a;
unsigned short b = 30000;
a = b; // 30000 在有符号范围内(合法)
cout << a; // 输出 30000
-
结果正常:30000 未超出
short int
的正数范围(32767),二进制解析一致。
五、错误示例与修正
错误示例:
unsigned short j = 65535;
short int i = j; // j=65535 → i=-1(二进制全1)
cout << i; // 输出 -1
修正方法:
-
范围检查:在赋值前验证值是否在有符号范围内。
if (j <= 32767) {i = j; } else {// 处理溢出 }unsigned short j = 65535; short int i; if (j <= 32767) {i = j; } else {i = 1;// 处理溢出 } cout << i;
-
显式类型转换(谨慎使用):
i = static_cast<short>(j); // 强制截断,可能丢失数据
六、总结表
特性 | 有符号整数(short int ) | 无符号整数(unsigned short ) |
---|---|---|
范围 | -32768 到 32767 | 0 到 65535 |
溢出行为 | 超出范围时按补码循环 | 超出范围时取模(如 65536 → 0) |
二进制解释 | 最高位为符号位,负数用补码 | 直接按正数解析 |
使用场景 | 需要表示正负数的场景(如温度) | 仅需非负数的场景(如计数器) |
七、扩展实例:32位整数溢出
unsigned int u = 4294967295; // 32位无符号最大值
int i = u; // 溢出为 -1(二进制全1)
cout << i; // 输出 -1