递归子程序(recursive subrountine)是指直接或间接调用自身的子程序。递归,调用递归子程序的做法,在处理具有重复模式的数据结构时,它是一个强大的工具。例如链表和各种类型的连接图,这些情况下,程序都需要追踪其路径。
无限递归
子程序对自身的调用是递归中最显而易见的类型。例如,下面的程序包含一个名为 Endless 的过程,它不间断地重复调用自身:
;无限递归 (Endless, asm)
INCLUDE Irvine32.inc
.data
endlessStr BYTE "This recursion never stops",0
.code
main PROC
call Endless
exit
main ENDP
Endless PROC
mov edx,OFFSET endlessStr
call WriteString
call Endless
ret ;从不执行
Endless ENDP
END main
当然,这个例子没有任何实用价值。每次过程调用自身时,它会占用 4 字节的堆栈空间让 CALL 指令将返回地址入栈。RET 指令永远不会被执行,仅当堆栈溢出时,程序终止。
递归求和
实用的递归子程序总是包含终止条件。当终止条件为真时,随着程序执行所有挂起的 RET 指令,堆栈展开。举例说明,考虑一个名为 CalcSum 的递归过程,执行整数 1 到 n 的加法,其中 n 是通过 ECX 传递的输入参数。CalcSum 用 EAX 返回和数:
;整数求和 (RecursiveSum. asm)
INCLUDE Irvine32.inc
.code
main PROC
mov ecx,5 ; 计数值 = 5
mov eax,0 ; 保存和数
call CalcSum ; 计算和数
L1: call WriteDec ; 显示 EAX
call Crlf ; 换行
exit
main ENDP
;--------------------------------------------------------
CalcSum PROC
; 计算整数列表的和数
; 接收: ECX = 计数值
; 返回: EAX = 和数
;--------------------------------------------------------
cmp ecx,0 ; 检查计数值
jz L2 ; 若为零则推出
add eax,ecx ; 否则,与和数相加
dec ecx ; 计数值递减
call CalcSum ; 递归调用
L2: ret
C