以階乘遞歸為例,觀察 MSVC Debug 版反組譯碼:
int factorial(int n) {
if (1 == n) return 1;
return n * factorial(n - 1);
}
; main 中呼叫 factorial(4) push 4 call @ILT+475(_factorial) add esp, 4 mov [fact], eax
factorial: push ebp mov ebp, esp sub esp, 0C0h ; 配置堆疊幀空間 (含安全檢查填充 0xCC) push ebx; push esi; push edi lea edi, [ebp-0C0h] mov ecx, 30h mov eax, 0CCCCCCCCh rep stos dword ptr es:[edi] ; 填充 0xCC 偵測堆疊溢位 ; 遞歸基底案例 cmp dword ptr [n], 1 jne RECURSIVE_CASE mov eax, 1 jmp EPILOGUE RECURSIVE_CASE: mov eax, [n] sub eax, 1 push eax ; 參數 n-1 入堆 call @ILT+475(_factorial) ; 遞歸呼叫自己 add esp, 4 imul eax, [n] ; eax = (n-1)! * n EPILOGUE: pop edi; pop esi; pop ebx add esp, 0C0h cmp ebp, esp call @ILT+320(__RTC_CheckEsp) mov esp, ebp pop ebp ret
push ebp / mov ebp, esp / sub esp, ... 建立獨立作用域。push eax 將 n-1 壓入呼叫者堆疊,被呼叫者從 [ebp+8] 取用。eax 傳遞 (n-1)!,呼叫者 imul 乘上 n。mov esp, ebp / pop ebp / ret 精確還原呼叫者堆疊指標。0xCC 填充、__RTC_CheckEsp)保證堆疊平衡。
#include "stack.h" // 假設提供 StackNode, CreateStack, Push, Pop
#define MAX_STACK 100
int main() {
StackNode* stk = CreateStack(MAX_STACK);
int n, tmp = 1, result = 1;
printf("Input n: "); scanf("%d", &n);
// 1. 參數入堆:n, n-1, ..., 1
while (n > 0) Push(stk, n--);
// 2. 出堆累乘:1 * 2 * 3 * ... * n
while (stk->top) {
Pop(stk, &tmp);
result *= tmp;
}
printf("%d! = %d\n", n, result);
return 0;
}
此版本將「系統呼叫堆疊」顯式化為「資料結構堆疊」,本質相同:遞歸 = 隱式堆疊 + 函數呼叫慣例。
1MB / 64B ≈ 16,000 層;超過即 Stack Overflow。ulimit -s、/STACK 連結旗標)、分治降低深度。