循环在汇编里只有一件事:把指令指针拨回去——它不是什么新东西,只是【比较 + 按条件跳回去】而已。
10.7 到 10.9 讲的是函数相关的机制,这一节回到第一章那个问题:循环在硬件上到底长什么样。
一、循环的全部秘密就一句
程序在硬件上是一条一条按顺序走的(1.3 讲过),走的位置由程序计数器记着。 循环做的事只有一件:在循环体末尾,让程序计数器跳回循环开头。 就这么简单——往前跳是分支,往回跳是循环(1.4 讲过)。 所以看汇编里的循环,只要找到那条【往回跳】的指令,循环的范围就确定了。
二、一个求和循环的五条指令
求 1 + 2 + 3 + 4,写成汇编是这样:
movl $0, %eax——累计值放 eax,先清零。
movl $1, %ecx——计数器放 ecx,从 1 开始。
loop: 标签下面四条:加当前的数、计数器加 1、跟 4 比一比、不超就跳回去。
整个循环体只有四条指令,核心是最后那条跳转。
三、逐圈看它是怎么停下来的
第 1 圈:eax 从 0 加到 1,ecx 变成 2,2 小于等于 4,跳。 第 2 圈:eax 变成 3,ecx 变成 3,还跳。 第 3 圈:eax 变成 6,ecx 变成 4,仍然跳。 第 4 圈:eax 变成 10,ecx 变成 5,这次不比 4 小,不跳了。 循环就停在这里——四圈下来 eax 正好是 10。
四、停下来的条件从哪儿来
cmpl $4, %ecx 自己不跳、也不改变流程——它只负责把比较结果记进标志位。
真正决定去哪儿的是后面那条 jle loop——它读标志位,决定跳不跳。
同一套机制,跳的方向不同,就成了循环或者分支(10.11 接着讲)。
所以循环没什么神秘的:它就是【条件不成立就不往回跳】。
五、动手 Demo:循环的工作原理
循环在汇编里只有一件事:把指令指针拨回去。 求 1 + 2 + 3 + 4,逐圈看它每一圈做了什么、什么时候停。
prog = [
("movl", "$0", "%eax"),
("movl", "$1", "%ecx"),
("label", "loop"),
("addl", "%ecx", "%eax"),
("incl", "%ecx"),
("cmpl", "$4", "%ecx"),
("jle", "loop"),
]
vm = VM(prog)
vm.run()
print("循环结束时的和", vm.reg["eax"])
eax, ecx, rnd = 0, 1, 0
while True:
rnd += 1
eax += ecx
ecx += 1
print("第 %d 圈 eax=%d ecx=%d 还跳吗=%s" % (rnd, eax, ecx, ecx <= 4))
if ecx > 4:
break
实跑输出:
--------------------------------------------------------------------
循环的工作原理
--------------------------------------------------------------------
**循环在汇编里只有一件事:把指令指针拨回去。**
求 1 + 2 + 3 + 4 的和,写成汇编是这样:
movl $0, %eax ; 累计值放 eax,先清零
movl $1, %ecx ; 计数器放 ecx,从 1 开始
loop:
addl %ecx, %eax ; 加上当前的数
incl %ecx ; 计数器加 1
cmpl $4, %ecx ; 跟 4 比一比
jle loop ; 还没超过 4 就跳回 loop
圈 加之前 eax 本圈加的 ecx 加完 eax incl 后 ecx ecx ≤ 4 吗 jle 跳吗
--------------------------------------------------------------------------------------------
1 0 1 1 2 是 跳
2 1 2 3 3 是 跳
3 3 3 6 4 是 跳
4 6 4 10 5 否 不跳
循环结束时的和 10
循环走了几圈 4 圈
循环体执行了 4 次
**看清最后一行:这一圈的 jle 没跳,循环就结束了。**
所以循环不是什么新东西——**它只是【比较 + 按条件跳回去】而已。**
实测:四圈之后 eax = 10,ecx = 5;最后一条 jle 没跳,循环就此结束。 循环不是什么新东西——它只是【比较 + 按条件跳回去】而已。
30 秒实验
- 把比较的值从 4 改成 10,算一算循环会走几圈、和是多少。
- 想一想:如果循环体里忘了让计数器加 1,会发生什么。
常见误区
- 以为循环是硬件里的一种专门结构。它就是往回跳。
- 以为循环结束是【自动判断】的。是跳转指令这一次没有跳。
自测三问(点开对答案)
1. 循环在硬件上是怎么实现的? —— 在循环体末尾让程序计数器跳回循环开头,不往回跳就走出循环。 2. 1 + 2 + 3 + 4 这个循环一共走了几圈? —— 四圈,eax 依次变成 1、3、6、10,最后 ecx 变成 5,条件不成立而退出。 3. 谁负责决定跳不跳? —— 跳转指令:它读取比较指令写下的标志位,决定是否改动程序计数器。- ☐ 下一节(10.11 条件分支的工作原理)
相关笔记
- 条件分支和循环的原理 — 这件事在硬件上的定义
- 决定程序流程的程序计数器 — 被拨动的是谁
- 条件分支的工作原理 — 跳的方向反过来就是分支
- 🔵 计算机基础 · 索引 — 硬件底层的入门课
- ⚙️ 程序是怎样跑起来的 · 索引