要准确判断两个带符号整数的大小关系,CPU必须同时参考符号标志位(SF)和溢出标志位(OF),而不能仅仅依赖符号标志位(SF)。
一、带符号整数比较原理详解
计算机中的比较操作通常由一条减法指令来实现,例如CMP A, B
指令,其在硬件层面的实际操作是计算 A−B ,但结果不回存,只根据计算结果设置相应的标志位。后续的条件转移指令(如jg
, jl
等)则根据这些标志位来判断是否跳转。
1. 为什么不能只看SF标志位?
一个常见的误区是:既然SF(Sign Flag)标志位表示结果的符号(SF=1为负,SF=0为正),那么比较 A 和 B 的大小,不就是看 A−B 的结果是正是负吗?
这种想法在不发生溢出的情况下是正确的。但一旦发生算术溢出,结果的符号位就会变得不可靠,甚至与真实结果的符号完全相反。
溢出(Overflow):当两个同号的数相加(或两个异号的数相减)后,结果超出了机器数所能表示的范围。在带符号数运算中,溢出会导致结果的符号位不正确。
-
正溢出:两个正数相加,结果大于了能表示的最大正数,变成了一个负数(例如8位系统中 127+1=−128)。
-
负溢出:两个负数相加,结果小于了能表示的最小负数,变成了一个正数(例如8位系统中 −127+(−2)=127)。
溢出标志位(OF) 就是用来检测这种情况的。当运算结果发生溢出时,OF=1
,否则OF=0
。
2. SF与OF的协同工作
为了正确判断带符号数的大小,必须将SF和OF结合起来。我们来分析 jg
(Jump if Greater) 和 jl
(Jump if Less) 的转移条件。
前提:CMP A, B
执行 A−B 操作。我们期望判断 A 是否大于/小于 B。
A > B (对应指令 jg, jnle)
-
转移条件: SF=OF AND ZF=0
-
逻辑分析: 我们希望 A−B 的真实结果是正数。
-
情况一:不溢出 (OF=0)
此时,计算结果的符号是可信的。要想 A−B>0,其结果必须为正数,即 SF=0。此时条件 SF=OF (0=0) 成立。
-
情况二:发生溢出 (OF=1)
此时,计算结果的符号是不可信的,与真实结果的符号相反。什么情况下 A−B 会溢出?只有“正数 - 负数”才可能导致正溢出(结果太大,看似为负)。例如,A 是一个较大的正数,B 是一个绝对值较大的负数,A−B 变成 A+(∣B∣),结果超出了最大正数范围,导致最终结果的符号位为1,即 SF=1。但我们知道,此时真实的 A 肯定是大于 B 的。此时条件 SF=OF (1=1) 也成立。
-
-
结论:无论是否溢出,只要 A>B,就必然满足 SF=OF。
ZF=0
条件是为了排除 A=B 的情况。
A < B (对应指令 jl, jnge)
-
转移条件: SF=OF AND ZF=0
-
逻辑分析: 我们希望 A−B 的真实结果是负数。
-
情况一:不溢出 (OF=0)
此时,计算结果的符号是可信的。要想 A−B<0,其结果必须为负数,即 SF=1。此时条件 SF=OF (1=0) 成立。
-
情况二:发生溢出 (OF=1)
此时,计算结果的符号是不可信的。什么情况下 A−B 会溢出?只有“负数 - 正数”才可能导致负溢出(结果太小,看似为正)。例如,A 是一个绝对值较大的负数,B 是一个较大的正数,A−B 的结果小于了最小负数范围,导致最终结果的符号位为0,即 SF=0。但我们知道,此时真实的 A 肯定是小于 B 的。此时条件 SF=OF (0=1) 也成立。
-
-
结论:无论是否溢出,只要 A<B,就必然满足 SF=OF。
ZF=0
同样是为了排除相等的情况。
二、图示
为了方便记忆,可以将带符号数比较的逻辑总结为下表:
逻辑条件 | 运算 (A−B) | OF | SF | 转移条件 | 是否满足 |
---|---|---|---|---|---|
A > B | 不溢出,结果为正 | 0 | 0 | SF=OF | ✅ |
A > B | 正溢出,“正-负”,结果看似为负 | 1 | 1 | SF=OF | ✅ |
A < B | 不溢出,结果为负 | 0 | 1 | SF=OF | ✅ |
A < B | 负溢出,“负-正”,结果看似为正 | 1 | 0 | SF=OF | ✅ |
而对于 jge
(大于等于) 和 jle
(小于等于),逻辑是类似的,只是放宽了对 ZF 的要求:
-
jge
(A ≥ B): SF=OF。 (允许 A=B 时结果为0,此时 ZF=1 但 SF=0,OF=0 依然满足 SF=OF) -
jle
(A ≤ B): SF=OF OR ZF=1。 (当 A=B 时,ZF=1,直接满足跳转条件)
三、常考点
-
混淆无符号数与有符号数跳转:这是最核心的考点。考生必须清晰地辨别指令助记符。
-
无符号数:
ja
(above),jb
(below)。依据:CF
和ZF
。 -
有符号数:
jg
(greater),jl
(less)。依据:SF
,OF
和ZF
。 -
je
(equal),jne
(not equal) 对两者通用,只看ZF
。
-
-
忽略CMP指令:条件转移指令本身不进行比较,它只检查标志位。题目中一定会有一个先行指令(如
CMP
,SUB
,ADD
等)来设置标志位,分析时必须以该指令的执行结果为依据。 -
对溢出判断不熟练:考题常常会精心设计操作数,使其运算结果恰好在溢出的边界上。考生必须熟练掌握溢出的判断方法:
-
方法一(双符号位法):使用补码的变形,用两个符号位表示。如果运算结果的两个符号位不同(01或10),则表示发生溢出。
-
方法二(单符号位法):OF=Cs⊕Cs−1,即符号位的进位和最高数值位的进位是否不同。对于减法 A−B,等效于计算 A+[B]补,此时 OF 是判断两个正数相加是否得到负数,或两个负数相加是否得到正数。
-