【总结笔记】数据的表示与运算(C语言底层视角)
本部分涵盖:补码本质与转换、无符号数/有符号数类型转换、底层加减法流程、整数乘法与溢出判断、IEEE 754 浮点数表示与精度边界。
一、补码的本质——“观察滤镜”
核心思想:内存中的二进制位模式(Bit Pattern)永远不变,改变的只是编译器如何解读它。
| 滤镜(类型) | 最高位含义 | 8 位表示范围 |
|---|---|---|
无符号(unsigned) | 数值位,权重 | |
有符号(int/char) | 符号位,权重 |
补码最高位的负权重本质(以8位为例):
模平移公式( 位):
- 最高位为 0:有符号值 = 无符号值 (相同)
- 最高位为 1:有符号值
二、补码转换四板斧
第一步:先看最高位!
| 最高位 | 判断 | 操作 |
|---|---|---|
| 0 | 正数 | 三码合一,直接加权求和,无需任何转换 |
| 1 | 负数 | 进入下面的转换流程 |
最高误区:看到补码就取反加 1!正数(最高位=0)绝对不要动!
负数补码的两种操作(严格区分)
| 目标 | 操作方式 | 符号位 |
|---|---|---|
| 求原码(写出机器数) | 符号位不动,数值位取反加 1 | 保持 1 |
| 求真值(算十进制是负几) | 全部所有位取反加 1,得绝对值,补负号 | 也取反 |
三种计算负数真值的方法(任选一种):
- 全位取反加 1:得绝对值,前面加负号
- 权重代入法:最高位乘 ,其余位正常加权
- 模公式:(如 )
移位口诀
- 左移(
<<):不分正负,低位补 0;高位被截断可能溢出 - 右移(
>>):- 无符号数(逻辑右移):高位补 0
- 有符号数(算术右移):高位补符号位(正数补0,负数补1)
三、C语言整数类型混合运算——底层加减法
黄金法则:绝对不要直接用十进制计算底层寄存器的内容!
解题标准流程(五步法)
Step 1:十进制 → 二进制补码(或十六进制)
Step 2:类型转换(赋值):位模式不变,只换解读方式
Step 3:减法 → 补码加法(A - B = A + (-B)的补码)
求 -B 的补码:对 B 的补码全部取反加 1
Step 4:二进制补码加法,超出字长的进位直接丢弃(截断)
Step 5:根据结果变量的类型,将低 n 位翻译回十进制
溢出判断(三种方法,任写一种)
- 双符号位法:若两个符号位不同(01或10),则溢出(01正溢,10负溢)
- 进位异或法:最高有效位进位 与符号位进位 ,若 则溢出
- 符号逻辑法:正+正=负,或 负+负=正,则溢出
无符号数与有符号数的区别
- 无符号数超字长:叫进位(Carry),不是溢出
- 有符号数超范围:才叫溢出(Overflow)
- **同一个加法器(ALU)**可以同时处理有符号和无符号运算,只需调整溢出检测逻辑
注意:
unsigned做减法时若结果为负(如unsigned i做0-1),会下溢变成 (约 40 亿),极易导致死循环!
四、整数乘法的底层实现与溢出判断
实现原理:乘法 = 循环加法 + 移位(竖式乘法)
位 × 位 → 产生 位完整乘积(绝对不会溢出)
溢出只发生在截断时
| 类型 | 溢出判断依据 |
|---|---|
| 无符号乘法 | 位乘积的高 位不全为 0 → 溢出 |
| 有符号乘法 | 截断后符号位发生异常(正×正变负,负×负变正)→ 溢出 |
三种实现效率
| 方式 | 速度 | 原理 |
|---|---|---|
| 纯软件(加法+移位指令循环) | 最慢 | 每步取指译码 |
| 带硬件支持的乘法指令 | 中等 | 微程序控制 ALU 自动循环 |
| 阵列乘法器 | 最快 | 纯组合逻辑,信号直通无需时钟 |
乘以 2 的幂次等价移位
五、IEEE 754 浮点数表示与精度边界
32 位单精度结构
真值计算公式:
| 符号 | 含义 |
|---|---|
| 符号位,0 为正,1 为负 | |
| 移码(偏置阶码),真实指数 | |
尾数,规格化数省略整数位 1.,实际精度为 23+1=24位 | |
| 规格化尾数(默认整数位为 1,不存储) |
特殊值速查
| (阶码) | (尾数) | 含义 |
|---|---|---|
| 全 0() | 全 0 | |
| 全 0() | 非 0 | 非规格化数(极小值) |
| 全 1() | 全 0 | (如 7F800000H = ) |
| 全 1() | 非 0 | NaN(非数,Not a Number) |
十进制转 IEEE 754 三步法
- 写成规格化二进制:如
- 提取 :,, 23个1
- 拼合十六进制:
0 10010110 11111111111111111111111→4BFFFFFFH
精度与溢出边界( 类型题)
| 类型 | 正常工作的最大 | 原因 |
|---|---|---|
int(32位) | 最大正数为 31 个 1(第 32 位是符号位) | |
float 精确无误差 | 有效精度 24 位, | |
float 不溢出 | 最大指数 ,需 |
易错:float 精度是 24 位不是 23 位!规格化数有隐含的整数位
1.,所以 23+1=24。
六、高频题型解题路线
题型一:求补码真值
看最高位
→ 0(正数):直接加权,三码合一
→ 1(负数):全位取反加 1 → 得绝对值 → 补负号
或直接用模公式:S = U - 2ⁿ
题型二:C语言混合运算底层结果
转补码 → 类型转换只换解读不改位 → 减法变补码加法 → 截断低n位 → 按类型解读
题型三:乘法是否溢出
算出 2n 位完整乘积
无符号:高 n 位有非0 → 溢出
有符号:截断后符号位异常(正变负/负变正)→ 溢出
题型四:IEEE 754 边界判断(代码题)
f(n)有 n+1 个1
int:n+1 ≤ 31,即 n ≤ 30
float精确:n+1 ≤ 24,即 n ≤ 23
float不溢出:n+1 ≤ 127,即 n ≤ 126
7F800000H = +∞(阶码全1,尾数全0)
七、高频易错汇总
| 错误 | 正确做法 |
|---|---|
| 正数也去取反加 1 | 最高位为 0 → 正数,三码合一,直接加权 |
| 求原码和求真值搞混 | 原码:符号位不动,数值位取反加 1;真值:全位取反加 1 求绝对值 |
| 直接用十进制算底层运算 | 先转二进制补码,在二进制做完再截断,最后按类型解读 |
unsigned 做减法不考虑下溢 | 0 - 1 对 unsigned 变成 ,极易死循环 |
| float 精度误以为 23 位 | 规格化有隐含 1.,实际精度 23+1=24 位 |
| 阶码直接当指数 | 真实指数 (要减偏置值) |
| 以为 2n 位乘积会溢出 | 2n 位中间结果永不溢出,溢出只发生在截断回 n 位时 |
| 有符号超范围叫进位 | 有符号超范围叫溢出(Overflow);无符号超字长叫进位(Carry) |