寫入程式test.c:
# include <stdio.h>int fun(int n){if (n==0)return 0;if(n==1)return 1;elsereturn n+fun(n-1);}int main(){fun(4);return 0;}
使用gcc –g test.c產生調試資訊,使用gdb偵錯工具,反組譯碼後得到彙編代碼(fun函數):
(gdb) disas funDump of assembler code for function fun: 0x004016b0 <+0>: push %ebp 0x004016b1 <+1>: mov %esp,%ebp 0x004016b3 <+3>: sub $0x18,%esp 0x004016b6 <+6>: cmpl $0x0,0x8(%ebp) 0x004016ba <+10>: jne 0x4016c3 <fun+19> 0x004016bc <+12>: mov $0x0,%eax 0x004016c1 <+17>: jmp 0x4016e3 <fun+51> 0x004016c3 <+19>: cmpl $0x1,0x8(%ebp) 0x004016c7 <+23>: jne 0x4016d0 <fun+32> 0x004016c9 <+25>: mov $0x1,%eax 0x004016ce <+30>: jmp 0x4016e3 <fun+51> 0x004016d0 <+32>: mov 0x8(%ebp),%eax 0x004016d3 <+35>: sub $0x1,%eax 0x004016d6 <+38>: mov %eax,(%esp) 0x004016d9 <+41>: call 0x4016b0 <fun> //遞迴調用函數fun() 0x004016de <+46>: mov 0x8(%ebp),%edx 0x004016e1 <+49>: add %edx,%eax 0x004016e3 <+51>: leave //函數調用結束 0x004016e4 <+52>: retEnd of assembler dump.
上面的彙編語句中,<+35>和<+38>行分別使得n減一和使得n-1入棧,然後繼續遞迴調用函數fun(),直到遇到遞迴的終止條件,使用leave和ret語句返回。
遞迴調用的過程是:
設定斷點,逐步執行後,查看棧幀後可得
(gdb) bt
#0 fun (n=1) at test.c:6
#1 0x004016de in fun (n=2) at test.c:9
#2 0x004016de in fun (n=3) at test.c:9
#3 0x004016de in fun (n=4) at test.c:9
#4 0x004016ff in main () at test.c:13
可見,fun函數每次遞迴調用,都會申請新的堆棧,如果遞迴調用的次數變多,執行的效率會降低很多。
繼續逐步執行,查看堆棧資訊
#0 infun (n=2) at test.c:10
#1 0x004016de in fun (n=3) at test.c:9
#2 0x004016de in fun (n=4) at test.c:9
#3 0x004016ff in main () at test.c:13
f(1)的堆棧已經被釋放
再次逐步執行,堆棧資訊為
#0 infun (n=3) at test.c:10
#2 0x004016de in fun (n=4) at test.c:9
#3 0x004016ff in main () at test.c:13
此時f(2)的堆棧已經被釋放
再次逐步執行,查看堆棧資訊
#0 infun (n=4) at test.c:10
#3 0x004016ff in main () at test.c:13
f(3)的堆棧被釋放
逐步執行,堆棧資訊為:
#0 mainat test.c:14
此時遞迴函式的調用已經結束