补码运算与整数溢出(下

前篇:补码运算与整数溢出(上-CSDN博客

目录

二进制截断(高位舍弃)

1. 无符号数截断

2. 有符号数截断

实操代码验证

算术移位、逻辑移位

1. 逻辑移位(无符号数使用)

2. 算术移位(有符号补码数使用,保留符号)

C 代码实操


二进制截断(高位舍弃)

和上一节 *符号扩展(位数变长)*正好相反:

位数变短,长类型赋值给短类型,直接砍掉高位,只保留低位。

硬件层面:不管有符号、无符号,截断动作完全相同,直接丢掉高位比特;差别只在最后如何解读剩下的低位。

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;
}

⚠重点

  1. 截断不是四舍五入,直接砍掉高位。
  2. 硬件丢弃高位这个动作,signed /unsigned 没有区别;区别在于剩下的二进制如何翻译成真值
  3. 先截断,再进行后续运算,顺序不要搞反。

对比表:扩展 vs 截断

表格

操作场景操作方式目标
符号 / 零扩展短→长高位补 0 / 补符号位保持数值不变
截断长→短直接舍弃高位位数强制缩小,数值大概率改变


思考

  1. 长字长转短字长,硬件怎么做?
  2. signed 和 unsigned 在截断时,硬件丢弃高位的动作是否不一样?
  3. 截断后的结果数值一定和原来相等吗?

1.截断

2.一样

3.不一定

  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。

表格汇总

表格

移位类型方向填充规则适用
逻辑移位左 / 右空位一律补 0unsigned 无符号数
算术移位低位补 0,符号位不动signed 有符号数
算术移位高位补符号位(0 正 1 负)signed 有符号数

坑点

  1. 有符号负数右移,不能直接补 0,必须补符号位 1(算术右移)
  2. 左移容易溢出;右移不会溢出
  3. 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. 逻辑移位,空位统一补什么?
  2. 有符号负数做算术右移,高位补什么?
  3. 算术移位和逻辑移位,哪一种用于无符号数?

1.0

2.1

3.逻辑位移

✅ 

  1. ✔ 逻辑移位,空出来的比特统一补 0
  2. ✔ 负数算术右移,高位填充符号位 1
  3. ✔ 逻辑移位用于无符号数

复盘

  • 逻辑移位:空位永远补 0,unsigned 专用
  • 算术移位:为有符号补码设计,算术右移高位复制符号位;算术左移低位补 0,符号位保持不变,一旦移出的高位不等于符号位,就发生溢出
  • 做题(计组硬件):signed 右移默认算术右移;写 C 代码时,标准没有强制规定所有编译器都实现算术右移,不能写依赖这个特性的代码

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值