是什么
-
定义:在计算机底层,无论有符号数还是无符号数,加减法统一使用补码并在同一个加法器(ALU)中进行。数据类型的转换(如
int与unsigned int的互相赋值)仅仅改变编译器对底层二进制序列的解释方式,绝不改变二进制序列本身。 -
大白话:CPU是个“没有感情的做题机器”,它不认识十进制,也不区分正负数。它只知道把你给的数字变成 0 和 1 的补码,然后像小学生列竖式一样加起来。至于算出来的结果是几,全看你(数据类型)怎么解读这串 0 和 1。
核心内容
1. 运算的黄金法则
-
绝对不要直接用十进制去算底层寄存器的内容!
-
第一步永远是:把十进制转换为底层的 二进制补码(或十六进制),在底层做完加减法、截断后,再根据变量类型翻译回十进制。
2. 无符号数(unsigned)的计算
-
原码、反码、补码完全相同。
-
解释方式:所有位都是数值位。8位字长范围:。
-
例:。
3. 有符号数(int)与负数的补码表示
-
解释方式:最高位是符号位(0为正,1为负),剩余位是数值位。8位字长范围:。
-
负数求补码公式:原码除符号位外,各位取反,末位加1。
(大白话:把正数的二进制全部反过来,再加1)
-
从负数补码求回真值(绝对值):同样是 各位取反,末位加1。
4. 底层加减法怎么算
-
加法: 直接在底层做补码加法。
-
减法: 转换为补码加法 。
-
截断规则:如果相加后超出字长(如 8 位机器算了 9 位出来),直接丢弃最高位的进位,只保留低 8 位。
例题
-
题目:假定在一个8位字长的计算机中运行如下C程序段:
C
unsigned int x = 134;
unsigned int y = 246;
int m = x;
int n = y;
int k1 = m - n;
求变量 在底层寄存器中的十六进制内容,以及 的十进制真值。
-
分析:
不能直接用十进制算 就完事了!必须走底层二进制,确认截断和补码转换的过程,否则稍微换个数字就会掉进溢出的坑里。
-
答案:
-
转二进制:,。
-
类型转换:
m = x,n = y。因为底层的二进制没有任何改变,所以 存的还是 , 存的还是 。 -
底层减法变加法:。
-
算负数补码: 的补码 = 按位取反加1 = (
1111 0110) 取反0000 1001,加10000 1010= 。 -
相加得寄存器结果: 底层 = (二进制
1001 0000)。 -
翻译回十进制: 声明为
int,最高位是 1,代表负数。对其求绝对值(取反加1):0110 1111+ 1 =0111 0000= 。因为是负数,所以真值为 。
溢出判断机制及发生溢出的语句
判断方法:计算机内部通常通过判断符号位的进位情况来检测有符号数的溢出。
常见方法有(任写一种即可得分):
-
双符号位法:运算结果的两个符号位如果不相同,则发生溢出(01正溢出,10负溢出)。
-
进位异或法:设最高有效位(数值位)向符号位的进位为 ,符号位产生的进位为 。若 ,则发生溢出。
-
符号逻辑法:若两个正数相加结果符号位为1,或两个负数相加结果符号位为0,则发生溢出。 能否利用同一个加法器辅助电路实现及理由 能。 理由:在计算机中,有符号整数和无符号整数均采用补码表示。不管是无符号数还是有符号数,其加减法运算在底层的位级操作是完全相同的。减法运算也会被转换为加上减数的负数补码的形式(即按位取反加1)。因此,这四种运算都可以通过同一个加法器(ALU)完成,只需在加法器的基础上增加控制逻辑处理进位和符号位即可。
⚠️ 易错点
Warning
最容易搞错的点:直接用十进制代入计算 正确做法: 先转成二进制补码,在二进制层面算完并截断后,再根据类型(有符号/无符号)把二进制翻译回十进制。
赋值改变数值的错觉 把
unsigned赋值给int,底层二进制绝对不变,只是最高位从“数值”变成了“符号”。无符号数没有“溢出(Overflow)” 无符号数加法超出字长叫进位(Carry)。溢出这个词在计算机组成原理中,特指有符号数相加/减时超出了表示范围(例如两个正数相加,符号位却变成了1)。