写程序时,少不了做判断。比如,用户输入的密码对不对?分数是不是及格了?这些看似简单的“是”或“不是”,在底层其实是靠汇编语言里的比较指令实现的。
比较指令干啥用的?
你可能以为计算机真能直接“比较”两个数大小,其实它没那么聪明。所谓的比较,其实是拿两个数做一次减法,然后偷偷看一下结果留下了什么痕迹——比如是不是为零、有没有借位、符号变没变。这些痕迹存在一个叫“标志寄存器”的地方,后面的跳转指令就靠它决定往哪走。
最常用的:CMP 指令
在 x86 汇编里,CMP 是最常见的比较指令。它的格式很简单:
CMP operand1, operand2
意思是用 operand1 - operand2 做减法,但不保存结果,只更新标志位。比如:
CMP EAX, 10
这行代码就是在看 EAX 寄存器里的值是不是等于 10。如果相等,零标志位(ZF)就会被设为 1;如果不等,ZF 就是 0。
比较之后怎么跳?
光比较没用,得根据结果决定下一步。这时候就得配合跳转指令。比如:
CMP ECX, 0
JZ loop_end
这段代码的意思是:如果 ECX 等于 0,就跳到 loop_end 标签处。这里的 JZ 就是“Jump if Zero”,依赖的就是前面 CMP 设置的 ZF 标志。
类似的还有:
JNE:不相等时跳(Jump if Not Equal)JG:大于时跳(Jump if Greater)JL:小于时跳(Jump if Less)
有符号和无符号的区别
别忘了,同一个二进制数,可以当有符号数,也可以当无符号数。比如 0xFF 和 0x01,如果当成无符号数,显然 FF 大;但如果是有符号数,FF 表示 -1,那就比 1 小了。
所以汇编里的跳转指令也得分情况:
- 比较无符号数:用
JA(Above)、JBE(Below or Equal) - 比较有符号数:用
JG(Greater)、JLE(Less or Equal)
搞混了就会出错。就像你拿温度计测水温,如果忘了它是摄氏还是华氏,判断就会出问题。
实际例子:判断成绩等级
假设你有个程序要判断学生成绩,EAX 里存着分数:
CMP EAX, 60
JL fail_label
; 及格了,继续往下执行
...
fail_label:
; 执行挂科提示
...
这段代码先比较分数是否小于 60,如果是,就跳去执行挂科逻辑。背后就是靠 CMP 更新了标志位,JL 根据符号和零标志做出判断。
别觉得汇编离你很远。你现在用的 App、游戏、操作系统,底层都有一大堆这样的比较指令在跑。它们像交通灯一样,控制着数据的流向,让程序知道什么时候该走,什么时候该停。