目录
二进制截断(高位舍弃)
和上一节 *符号扩展(位数变长)*正好相反:
位数变短,长类型赋值给短类型,直接砍掉高位,只保留低位。
硬件层面:不管有符号、无符号,截断动作完全相同,直接丢掉高位比特;差别只在最后如何解读剩下的低位。
1. 无符号数截断
按剩下低位,直接当作无符号数解读。 示例:16 位 unsigned 0x12AB 截断为 8 位 16 位:0001 0010 1010 1011 砍掉高 8 位,保留低 8 位 10101011,值 = 171
2. 有符号数截断
同样直接丢弃高位;保留的低位按照补码规则解读(最高位作为新的符号位)。 示例:32 位 int 0x0000FF01,赋值给 8 位 char 低 8 位是 11110001,当作 8 位补码,对应真值 -15。
实操代码验证
c
#include <stdio.h>
int main(void)
{
int val = 0x1234FF01;
char c = val; //截断,保留低8位
unsigned char uc = val;//截断,保留低8位
printf("c = %d\n", c);
printf("uc = %u\n", uc);
return 0;
}
⚠重点
- 截断不是四舍五入,直接砍掉高位。
- 硬件丢弃高位这个动作,signed /unsigned 没有区别;区别在于剩下的二进制如何翻译成真值。
-
先截断,再进行后续运算,顺序不要搞反。
对比表:扩展 vs 截断
表格
| 操作 | 场景 | 操作方式 | 目标 |
|---|---|---|---|
| 符号 / 零扩展 | 短→长 | 高位补 0 / 补符号位 | 保持数值不变 |
| 截断 | 长→短 | 直接舍弃高位 | 位数强制缩小,数值大概率改变 |
思考
- 长字长转短字长,硬件怎么做?
- signed 和 unsigned 在截断时,硬件丢弃高位的动作是否不一样?
- 截断后的结果数值一定和原来相等吗?
:
1.截断
2.一样
3.不一定
:
✅
- ✔ 直接舍弃高位,保留低位,也就是截断
- ✔ 硬件层面丢弃高位的动作完全一样;差异只在对剩下二进制位的解读方式
- ✔ 不一定。截断会丢失高位信息,绝大多数场景数值会变;极少数情况高位本来就是 0,数值刚好不变。
小结
- 扩展:短→长,尽量保住原值
- 截断:长→短,砍掉高位,信息可能丢失
- 硬件动作不分 signed/unsigned;解释二进制的规则才区分 signed/unsigned
算术移位、逻辑移位
移位:二进制整体向左 / 向右移动,移出的位丢掉,空出来的高位 / 低位填充比特。
两类移位:逻辑移位、算术移位
1. 逻辑移位(无符号数使用)
无论左移、右移,空出来的位全部补 0
- 逻辑左移:全部比特左移,低位补 0,最高位移出丢弃
- 逻辑右移:全部比特右移,高位补 0,最低位移出丢弃 适用:unsigned 无符号数
逻辑左移等价 ×2;逻辑右移等价 ÷2(仅无符号、无溢出时)
2. 算术移位(有符号补码数使用,保留符号)
核心规则:符号位永远不动
- 算术左移:整体左移,低位补 0;符号位不变。移出的高位如果和符号位不一致 → 溢出
- 算术右移:整体右移,空位填充符号位(正数补 0,负数补 1)
示例:8 位补码,-4,二进制11111100 算术右移 1 位 → 11111110,等于 - 2,等价除以 2。
表格汇总
表格
| 移位类型 | 方向 | 填充规则 | 适用 |
|---|---|---|---|
| 逻辑移位 | 左 / 右 | 空位一律补 0 | unsigned 无符号数 |
| 算术移位 | 左 | 低位补 0,符号位不动 | signed 有符号数 |
| 算术移位 | 右 | 高位补符号位(0 正 1 负) | signed 有符号数 |
坑点
- 有符号负数右移,不能直接补 0,必须补符号位 1(算术右移)
- 左移容易溢出;右移不会溢出
- C 语言:有符号数右移,标准没有强制规定一定算术右移(不同编译器行为不同,做题按计组硬件:算术右移)
C 代码实操
c
#include <stdio.h>
void print_bin(char val)
{
for(int i=7;i>=0;i--)
putchar( val & (1<<i) ? '1':'0' );
putchar('\n');
}
int main(void)
{
signed char x = -4;
print_bin(x);
x = x >> 1; //算术右移
print_bin(x);
return 0;
}
思考
- 逻辑移位,空位统一补什么?
- 有符号负数做算术右移,高位补什么?
- 算术移位和逻辑移位,哪一种用于无符号数?
:
1.0
2.1
3.逻辑位移
:
✅
- ✔ 逻辑移位,空出来的比特统一补 0
- ✔ 负数算术右移,高位填充符号位 1
- ✔ 逻辑移位用于无符号数
复盘
- 逻辑移位:空位永远补 0,unsigned 专用
- 算术移位:为有符号补码设计,算术右移高位复制符号位;算术左移低位补 0,符号位保持不变,一旦移出的高位不等于符号位,就发生溢出
- 做题(计组硬件):signed 右移默认算术右移;写 C 代码时,标准没有强制规定所有编译器都实现算术右移,不能写依赖这个特性的代码

324

被折叠的 条评论
为什么被折叠?



