C语言递归调用中栈内存溢出预检测的实现方法问询
C语言递归栈溢出预检测方案
针对你给出的递归函数和限定栈内存的场景,以下是基于指针的可行检测方案,核心思路是通过当前栈位置与栈边界的对比,判断剩余空间是否能容纳下一个递归栈帧。
1. 明确栈边界
首先固定模拟栈的上下边界:
// 题目限定的栈内存数组 char stackmemory[100]; // 栈的底部(栈增长的下限,低地址端) char *const STACK_BOTTOM = stackmemory; // 栈的顶部(初始栈位置,高地址端) char *const STACK_TOP = stackmemory + 99;
C语言栈从高地址向低地址增长,每次递归调用会在当前栈位置的低地址方向分配新栈帧。
2. 估算单个递归栈帧的大小
递归函数的栈帧至少包含:
- 函数返回地址(32位平台4字节,64位平台8字节)
- 函数参数(这里是
int num,4字节) - 栈帧基指针(32位平台4字节,64位平台8字节)
保守估算的话,32位平台取12字节,64位平台取20字节(覆盖编译器可能的额外对齐空间),足够应对题目场景。
3. 修改递归函数,添加栈检测逻辑
直接在递归调用前加入剩余栈空间判断,代码如下:
#include <stddef.h> char stackmemory[100]; char *const STACK_BOTTOM = stackmemory; // 单个栈帧大小,根据平台调整 const size_t STACK_FRAME_SIZE = 12; void recursion(int num) { if (num <= 1) { return; } // 用局部变量地址获取当前栈位置 char current_pos; // 计算剩余栈空间:当前位置到栈底的字节数 ptrdiff_t remaining = ¤t_pos - STACK_BOTTOM; // 剩余空间不足容纳下一个栈帧,终止递归 if (remaining < STACK_FRAME_SIZE) { return; } recursion(num / 10); }
4. 更精准的栈指针直接读取方案(可选)
如果编译器支持内联汇编,可直接读取栈指针寄存器(ESP/RSP)获取当前栈位置,比局部变量地址更精准:
#include <stddef.h> char stackmemory[100]; char *const STACK_BOTTOM = stackmemory; const size_t STACK_FRAME_SIZE = 12; // 根据平台定义栈指针读取宏 #ifdef __i386__ #define GET_STACK_PTR() ({ uint32_t esp; __asm__ volatile ("mov %%esp, %0" : "=r"(esp)); (char*)esp; }) #elif defined(__x86_64__) #define GET_STACK_PTR() ({ uint64_t rsp; __asm__ volatile ("mov %%rsp, %0" : "=r"(rsp)); (char*)rsp; }) #endif void recursion(int num) { if (num <= 1) { return; } char *current_sp = GET_STACK_PTR(); ptrdiff_t remaining = current_sp - STACK_BOTTOM; if (remaining < STACK_FRAME_SIZE) { return; } recursion(num / 10); }
注意事项
- 栈帧大小务必取保守值,避免因编译器优化、内存对齐等因素导致计算偏差。
- 题目用
stackmemory模拟栈,实际系统中栈边界需通过系统API获取,此场景直接用数组边界即可。
内容的提问来源于stack exchange,提问作者Dave_hmster
相关产品推荐
相关产品推荐

