21xrx.com
2024-09-20 00:29:26 Friday
登录
文章检索 我的文章 写文章
如何在C++中打印函数调用栈
2023-07-10 04:43:12 深夜i     --     --
C++ 函数调用栈 打印

函数调用栈是程序运行时的重要组成部分,它记录了程序在运行时调用函数的过程。在C++中,我们可以通过一些技巧打印出函数调用栈,来帮助我们更好地理解程序运行过程以及排查错误。下面就让我们一起来了解如何在C++中打印函数调用栈吧!

首先,我们需要知道C++的函数调用栈是由堆栈(stack)来实现的。每当程序调用一个新的函数时,该函数会被加入堆栈的顶部,当函数返回时,该函数会被弹出堆栈,让栈顶指向上一个被调用的函数。因此,我们可以通过递归调用一个函数来打印函数调用栈。

接下来,我们可以利用C++的栈帧结构来获取函数调用栈。栈帧是一个用来存储函数调用信息的数据结构,在每次函数调用时,一个新的栈帧就会被创建。我们可以利用这个新的栈帧来获取函数的调用信息,并将其存储在一个字符串中,最终打印出整个函数调用栈。

下面是一段C++代码实现打印函数调用栈的过程:


#include <iostream>

#include <string>

using namespace std;

string get_stack_trace(int depth = 0)

{

  const int max_depth = 10; // 最大打印深度

  if (depth >= max_depth)

    return "";

  void* trace[max_depth];

  int size = backtrace(trace, max_depth);

  char** symbols = backtrace_symbols(trace, size);

  string ret;

  for (int i = 1; i < size && symbols != nullptr; i++) {

    Dl_info info;

    if (dladdr(trace[i], &info) && info.dli_sname != nullptr) {

      char* demangled = nullptr;

      int status = -1;

      demangled = abi::__cxa_demangle(info.dli_sname, nullptr, 0, &status);

      ret += string(i * 2, ' ') + (status == 0 ? demangled : symbols[i]) + "\n";

      free(demangled);

    } else {

      ret += string(i * 2, ' ') + symbols[i] + "\n";

    }

  }

  free(symbols);

  return ret;

}

void func_c()

{

  cout << "In function C." << endl;

  cout << get_stack_trace(1) << endl;

}

void func_b()

{

  cout << "In function B." << endl;

  func_c();

}

void func_a()

{

  cout << "In function A." << endl;

  func_b();

}

int main()

{

  func_a();

  return 0;

}

这段代码使用了C++11新增的`backtrace`和`backtrace_symbols`函数来获取当前函数调用栈的信息。在这个函数中,我们首先定义了一个最大深度`max_depth`,防止函数调用栈过深导致的死循环。然后,我们利用`backtrace`和`backtrace_symbols`函数来获取当前函数调用栈的信息,并将其存储在一个字符串中返回。在返回的字符串中,我们使用一个`string`对象来保存栈信息,并以递进的方式缩进每一个栈帧的信息。

最后,在`main`函数中调用`func_a`函数,并打印函数调用栈。

通过以上的代码,我们可以清晰地看到函数调用栈的内容,这可以帮助我们更好地理解程序的运行过程,并且可以帮助我们更快地排查程序中的错误。

  
  

评论区

{{item['qq_nickname']}}
()
回复
回复