你能确定 C 中的堆栈深度吗?
Can you determine stack depth in C?
我想知道 C 中是否有一个函数(让我们将其命名为 int get_stack_depth()),returns 当前函数的数量在栈上执行。例如:
int foo(){
return get_stack_depth();
}
int bar2(){
return get_stack_depth();
}
int bar1(){
return bar2();
}
int bar(){
return bar1();
}
int main(){
get_stack_depth(); // = 0
foo(); // = 1
bar(); // = 3
return 0;
}
我想用它来调试信息,其中每个 printf 将包含 get_stack_depth() 缩进以提高可读性。如果这是编译器相关的,或者任何其他相关的,我会接受所有的约束;现在我想知道这是否至少在某个地方得到支持。
编辑:建议重复的答案对我一点帮助都没有,正如此处接受的答案所暗示的那样,您无法仅根据堆栈的大小来确定堆栈上有多少个函数;信息根本不存在。
C 中堆栈的确切机制是特定于实现的,因此没有单一、正确、标准的方法来查找堆栈深度。不过,有一些方法可以模拟这种行为。
使用计数器。定义一个全局的unsigned depth
,在每个你关心栈深度的函数中,开头注入depth++
,结尾注入depth--
。这显然是更繁琐的方法,如果不进行递增或递减,很容易出现很多令人沮丧的问题。
检查堆栈指针。在 x86 系统(几乎所有台式机和笔记本电脑设备)上,堆栈向下增长,这意味着进入函数调用将减少堆栈指针的值。在许多情况下(但不是全部,例如启用优化时)堆栈指针寄存器 %rsp
指向当前函数堆栈帧的“顶部”。获取此值的一种相当 hacky 的方法是将其分配给一个变量:register uint64_t rsp asm ("rsp");
。值越低,堆栈的深度越大。
不幸的是,函数调用之间递减的大小取决于该函数的堆栈帧有多大——如果一个函数将一个大数组声明为局部变量,那么它的函数的堆栈指针会低得多调用,因为数组消耗了更多 space。
最终,我所知道的找到准确的函数调用回溯的唯一可靠方法是 运行 调试器中的程序,例如 gdb
并发出 backtrace
命令,这将打印当前调用堆栈。当 运行 独立于任何调试器时,程序似乎无法使用这种支持。
您尝试过使用 backtrace() 吗?
例如:
#include <execinfo.h>
unsighed int getDepth(){
const unsigned int max_depth = 200;
void* buffer[max_depth];
return backtrace(buffer, max_depth)-5;
}
-5
在那里是因为 main
上面有一些函数(由 libc 添加)我想忽略。但是,如果您想自动计算,请将我的函数更改为
int get_stack_depth(int set_caller_as_root){
static int root_depth = 0;
if (set_caller_as_root){
root_depth = get_stack_depth(0) - 1;
}
const int max_depth = 200;
void* buffer[max_depth];
return backtrace(buffer, max_depth) - root_depth;
}
并将您的代码更新为
int foo(){
return get_stack_depth(0);
}
int bar2(){
return get_stack_depth(0);
}
int bar1(){
return bar2();
}
int bar(){
return bar1();
}
int main(){
printf("%d\n", get_stack_depth(1)); // = 0
printf("%d\n", foo()); // = 1
printf("%d\n", bar()); // = 3
return 0;
}
这会产生正确的预期结果。
请注意 execinfo.h
默认情况下未安装在 windows 10 上(它安装在 linux 上)。
我想知道 C 中是否有一个函数(让我们将其命名为 int get_stack_depth()),returns 当前函数的数量在栈上执行。例如:
int foo(){
return get_stack_depth();
}
int bar2(){
return get_stack_depth();
}
int bar1(){
return bar2();
}
int bar(){
return bar1();
}
int main(){
get_stack_depth(); // = 0
foo(); // = 1
bar(); // = 3
return 0;
}
我想用它来调试信息,其中每个 printf 将包含 get_stack_depth() 缩进以提高可读性。如果这是编译器相关的,或者任何其他相关的,我会接受所有的约束;现在我想知道这是否至少在某个地方得到支持。
编辑:建议重复的答案对我一点帮助都没有,正如此处接受的答案所暗示的那样,您无法仅根据堆栈的大小来确定堆栈上有多少个函数;信息根本不存在。
C 中堆栈的确切机制是特定于实现的,因此没有单一、正确、标准的方法来查找堆栈深度。不过,有一些方法可以模拟这种行为。
使用计数器。定义一个全局的
unsigned depth
,在每个你关心栈深度的函数中,开头注入depth++
,结尾注入depth--
。这显然是更繁琐的方法,如果不进行递增或递减,很容易出现很多令人沮丧的问题。检查堆栈指针。在 x86 系统(几乎所有台式机和笔记本电脑设备)上,堆栈向下增长,这意味着进入函数调用将减少堆栈指针的值。在许多情况下(但不是全部,例如启用优化时)堆栈指针寄存器
%rsp
指向当前函数堆栈帧的“顶部”。获取此值的一种相当 hacky 的方法是将其分配给一个变量:register uint64_t rsp asm ("rsp");
。值越低,堆栈的深度越大。不幸的是,函数调用之间递减的大小取决于该函数的堆栈帧有多大——如果一个函数将一个大数组声明为局部变量,那么它的函数的堆栈指针会低得多调用,因为数组消耗了更多 space。
最终,我所知道的找到准确的函数调用回溯的唯一可靠方法是 运行 调试器中的程序,例如 gdb
并发出 backtrace
命令,这将打印当前调用堆栈。当 运行 独立于任何调试器时,程序似乎无法使用这种支持。
您尝试过使用 backtrace() 吗? 例如:
#include <execinfo.h>
unsighed int getDepth(){
const unsigned int max_depth = 200;
void* buffer[max_depth];
return backtrace(buffer, max_depth)-5;
}
-5
在那里是因为 main
上面有一些函数(由 libc 添加)我想忽略。但是,如果您想自动计算,请将我的函数更改为
int get_stack_depth(int set_caller_as_root){
static int root_depth = 0;
if (set_caller_as_root){
root_depth = get_stack_depth(0) - 1;
}
const int max_depth = 200;
void* buffer[max_depth];
return backtrace(buffer, max_depth) - root_depth;
}
并将您的代码更新为
int foo(){
return get_stack_depth(0);
}
int bar2(){
return get_stack_depth(0);
}
int bar1(){
return bar2();
}
int bar(){
return bar1();
}
int main(){
printf("%d\n", get_stack_depth(1)); // = 0
printf("%d\n", foo()); // = 1
printf("%d\n", bar()); // = 3
return 0;
}
这会产生正确的预期结果。
请注意 execinfo.h
默认情况下未安装在 windows 10 上(它安装在 linux 上)。