有符号与无符号:补码、类型转换与溢出
2026/9/1大约 3 分钟
C语言有符号与无符号:补码、类型转换与溢出
C 语言里最容易出错的地方之一:
有符号数和无符号数混合运算,会发生类型转换;整数通常以补码形式存储。
一、有符号整数通常用补码存储
以 8 位 char 为例:
127 = 0111 1111加 1:
0111 1111
+ 0000 0001
-----------
1000 00008 位 signed char 中:
1000 0000按补码解释就是:
-128所以:
signed char a = 127;
a++;
printf("%d\n", a);结果通常是:
-128这里要注意:
内存里存的是位模式,CPU 按补码解释有符号整数。
二、为什么 char a = 127; a++; 会变成负数?
因为 8 位有符号整数范围:
-128 ~ 127已经到最大值:
0111 1111再加 1:
1000 0000于是从:
+127绕到了:
-128这就是整数溢出。
三、有符号数和无符号数混合运算
例如:
int a = -7;
unsigned int b = 3;
a + b
这里不会简单按照:
```text
-7 + 3 = -4理解。
由于 unsigned int 参与运算,a 会转换成 unsigned int。转换时,-7 的原值不是直接按“负号”参与运算,而是先转换为对应的无符号值。对于常见的 32 位 unsigned int,转换结果的位模式为:
-7 的补码:
11111111 11111111 11111111 11111001这里要区分:
-7的原码:10000000 00000000 00000000 00000111-7的反码:11111111 11111111 11111111 11111000-7的补码:11111111 11111111 11111111 11111001
计算机中有符号整数通常使用补码存储和参与运算。因此,a 转换为 unsigned int 后,保留的仍是这组补码位模式,只是改用无符号类型解释:
11111111 11111111 11111111 11111001
= 4294967289所以实际进行的是:
11111111 11111111 11111111 11111001
+00000000 00000000 00000000 00000011
---------------------------------------
11111111 11111111 11111111 11111100这个二进制数按无符号数解释:
11111111 11111111 11111111 11111100
= 4294967292如果把同样的位模式按有符号 int 的补码解释:
11111111 11111111 11111111 11111100
↓
-4因此:
printf("%u\n", a + b);看到的是:
4294967292而:
printf("%d\n", a + b);按有符号补码方式解释这个位模式,结果是:
-4四、为什么同一组二进制可以打印出不同结果?
因为:
0xFFFFFFFC只是一组二进制位。
怎么解释取决于类型:
unsigned int
→ 4294967292
int
→ -4所以要记住:
二进制位本身没有正负,类型决定如何解释它。
五、打印格式也必须匹配
int a = -1;
unsigned int b = 3;不要随便:
printf("%u", a); // 类型不匹配应该:
printf("%d", a);
printf("%u", b);其中:
%d → int
%u → unsigned int六、最终记忆
整数
↓
以二进制位形式存储
↓
有符号整数通常按补码解释混合运算:
int + unsigned
↓
发生类型转换
↓
可能把负数转换成很大的无符号数例如:
-7
↓ 转 unsigned
4294967289而:
127 + 1在 8 位有符号整数中:
0111 1111
↓ +1
1000 0000
↓ 补码解释
-128先看类型,再看位模式,最后看输出格式。

