Keyboard shortcuts

Press or to navigate between chapters

Press ? to show this help

Press Esc to hide this help

分支与循环

复习

  • 汇编器:通过两遍扫描,把符号汇编成机器码
  • 高级语言:再加一层:从“控制机器”转向“描述问题”
  • 变量、类型与表达式:名字如何代表数据,表达式如何变成运算

TL;DR

  • 判断落到机器上,是“比较 + 条件跳转”
  • 比较的结果记在状态标志里,跳转指令根据标志决定改不改 PC
  • 循环就是“往回跳”,再加上一个“该不该停下”的判断
  • 顺序、选择、循环三种结构,构成了所有程序

正文

  到现在为止,我们的程序只会一条道走到黑。可现实里更像这样:如果分数及格就显示“通过”;把 1 到 100 加起来;只要还没做完就再来一遍。要表达这些,程序得学会 拐弯回头

判断:比较加跳转

  先看最简单的一句:

if x > y:
    max = x
else:
    max = y

  人一眼就懂,机器却只会计算和跳转。它怎么知道 x 大于 y

  办法还是计算:把两个数 相减 。如果 x - y 是正数,说明 x 更大;是 0,说明相等;是负数,说明 x 更小。这一步相减,就叫 比较

  我们把比较写成一条指令 CMP:它做减法、设置状态标志,但 不保存减法结果 ——我们关心的不是差是多少,而是差的正负。然后,再由跳转指令去看标志:

      LOAD A, [x]
      LOAD B, [y]
      CMP  A, B
      JGT  then        ; 若 x > y,跳到 then
      MOV  R, B        ; 否则 max = y
      STORE [max], R
      JMP  end
then: MOV  R, A        ; max = x
      STORE [max], R
end:  HALT

  MOV 是“把一个寄存器里的值搬到另一个寄存器”。这里的 JGT 是“大于则跳转”。除了它,还有一批类似的指令:JZ(等于 0 则跳)、JN(为负则跳)、JLE(小于等于则跳)……名字不用记, 它们全都是先看标志,再决定改不改 PC。

  顺带一提,前面几章那个 Z 标志,就是在这类地方派上用场的:ALU 负责产生标志,跳转指令负责根据标志选路。

循环:往回跳

  再看“把 1 到 n 加起来”:

sum = 0
i = 1
while i <= n:
    sum = sum + i
    i = i + 1

  翻译成汇编:

      ; 这里假设 sum、i、n、one 都已就位
loop: LOAD A, [i]
      LOAD B, [n]
      CMP  A, B
      JGT  done         ; i > n 时结束
      LOAD A, [sum]
      LOAD B, [i]
      ADD  R, A, B
      STORE [sum], R    ; sum = sum + i
      LOAD A, [i]
      LOAD B, [one]
      ADD  R, A, B
      STORE [i], R      ; i = i + 1
      JMP  loop         ; 回到开头
done: HALT

  对照着看:while 的判断变成“比较 + 不满足就跳出”;循环体照抄;最后一条 JMP loop 把 PC 改回开头,于是这几行被反复执行。

  循环,本质上就是“往回跳”。 只不过每次跳之前,都要问一句“还该继续吗”。

三种结构

  无论程序多复杂,拆开来都逃不出三种结构:

  1. 顺序 :一条接一条往下走
  2. 选择 :满足条件走这边,否则走那边(ifelse
  3. 循环 :满足条件就一直重复(whilefor

  它们全都靠“比较 + 条件跳转”实现。高级语言把这层跳转包装成了 ifwhile,我们就再也不用亲手写 JMP 了——这正是上一章说的“加一层”。

  不过,上面这些程序还有一个共同点:它们都是从头写到尾的一长条。如果某段逻辑要反复使用,难道每次都要重抄一遍?下一章,我们给它起个名字,让它能按需调用。

思考题

  如果把循环里的 i = i + 1 忘了写,会发生什么?从 PC 和标志的角度,解释一下为什么程序会“停不下来”。

小结

知识点

  • 判断由“比较 + 条件跳转”实现
  • 比较设置状态标志,条件跳转根据标志决定是否改 PC
  • 循环是“往回跳”加一个结束判断
  • 顺序、选择、循环三种基本结构

参考资料

  1. Wikipedia(zh):控制流:程序中的顺序、选择与循环
  2. Wikipedia(zh):条件跳转:分支与跳转

思考题答案(仅供参考)

  忘了 i = i + 1i 永远不变,于是“i > n”这个条件永远不成立,JGT done 一直不跳,JMP loop 每次都把 PC 带回开头,程序就一直在循环里打转。它不是“卡住”,而是忠实地执行了程序——只是程序本身没有让它停下的条件。

协议

  本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。

封面图

设计师 | 南国微雪