CMP A, B 之后,SF 和 OF 的每一种组合为什么能正确判断 A ≥ B
所有计算均使用 CPU 真实执行方式:A + (~B) + 1
以 8 位有符号数为例(范围 −128 ~ +127),CMP A, B 即 A − B,CPU 内部执行 A + (~B) + 1:
| 情况 | A − B 结果 | SF | OF | SF = OF? | 跳转? |
|---|---|---|---|---|---|
| ① A > B,无溢出 | 正数 | 0 |
0 |
0 = 0 ✔ | 跳转 |
| ② A = B,无溢出 | 零 | 0 |
0 |
0 = 0 ✔ | 跳转 |
| ③ A < B,无溢出 | 负数 | 1 |
0 |
1 ≠ 0 ✘ | 不跳 |
| ④ A < B,有溢出 | 符号被翻转 | 0 |
1 |
0 ≠ 1 ✘ | 不跳 |
| ⑤ A > B,有溢出 | 符号被翻转 | 1 |
1 |
1 = 1 ✔ | 跳转 |
例子:A = 50,B = 20,真实结果 50 − 20 = 30,在 −128~+127 范围内,无溢出。
分析:结果 30 是正数,最高位为 0,所以 SF=0。Carry_In 和 Carry_Out 都是 1,进位"穿过"了 bit7,符号位未被篡改,OF=0。SF 如实反映了"结果为正",不需要任何纠正。SF=OF=0,XOR 结果为 0,说明 A−B ≥ 0,即 A ≥ B,JGE 跳转,正确。
例子:A = 30,B = 30,真实结果 30 − 30 = 0,无溢出。
分析:结果为 0,最高位为 0,SF=0。Carry_In 和 Carry_Out 都是 1,进位穿过了 bit7,OF=0。零既不是正数也不是负数,但在 JGE(大于等于)的语义中,等于也应该跳转。SF=OF=0 满足条件,跳转,正确。
例子:A = 20,B = 50,真实结果 20 − 50 = −30,在 −128~+127 范围内,无溢出。
分析:结果 −30 是负数,最高位为 1,SF=1。Carry_In 和 Carry_Out 都是 0,进出一致,符号位未被篡改,OF=0。SF 如实反映了"结果为负",不需要纠正。SF≠OF,XOR 结果为 1,说明 A−B < 0,即 A < B,JGE 不跳,正确。
例子:A = −100,B = 80,真实结果 −100 − 80 = −180,超出 −128 的下限,发生负溢出。
分析:结果的最高位是 0,所以 SF=0,看起来是正数。但这是假象——真实结果 −180 是负数,只是被截断后符号翻转了。Carry_In=0 但 Carry_Out=1,进出不一致,说明进位在 bit7 处"凭空产生",篡改了符号位,OF=1。
推理过程:
例子:A = 100,B = −50,真实结果 100 − (−50) = 150,超出 +127 的上限,发生正溢出。
分析:结果的最高位是 1,所以 SF=1,看起来是负数。但这又是假象——真实结果 +150 是正数,只是超过了 +127 被截断后符号翻转了。Carry_In=1 但 Carry_Out=0,进出不一致,说明低位进位"被困在"了 bit7 里,篡改了符号位,OF=1。
推理过程:
| OF | SF | 真实符号 = SF⊕OF | 含义 | JGE 跳转? |
|---|---|---|---|---|
0(SF 可信) |
0 |
0 → 正/零 | A ≥ B | 跳转(①②) |
0(SF 可信) |
1 |
1 → 负 | A < B | 不跳(③) |
1(SF 说谎) |
0 |
1 → 负(取反) | A < B | 不跳(④) |
1(SF 说谎) |
1 |
0 → 正(取反) | A > B | 跳转(⑤) |
SF 是"加了噪声的符号",OF 是噪声本身。
OF=0 时,没有噪声,SF 可以直接信任。
OF=1 时,噪声存在,SF 的含义被翻转了,需要取反才能还原真实符号。
SF XOR OF 一步完成了去噪:结果为 0 表示真实结果非负(A ≥ B),结果为 1 表示真实结果为负(A < B)。
JGE 的条件 SF=OF 等价于 SF XOR OF = 0,即真实结果 ≥ 0,即 A ≥ B。五种情况全部正确。