C++异常中的堆栈跟踪就是当程序抛出异常时,能够把抛出异常的语句所在的文件名、函数以及其它上层函数信息都打印出来。
堆栈跟踪意义重大:在实际的生产过程中,发现代码中bug要比解决bug更加费事费力,而发生异常时的堆栈信息可以帮助我们更快的发现程序中的问题,有助于加快开发。
C++不像java,在异常类中有提供堆栈跟踪功能,C++标准库中的std::exception及其子类中并没有提供堆栈跟踪功能,所以我们需要给C++中的异常类添加上可以查看异常发生时堆栈信息的功能。
在具体的实现之前,我们先来看些前提知识:
获取堆栈信息
首先应该考虑的是我们该如何获取到堆栈信息?在Linux平台上提供了如下API用来获取和查看堆栈信息 [1]:
#include <execinfo.h>
int backtrace(void **buffer, int size);
char **backtrace_symbols(void *const *buffer, int size);
void backtrace_symbols_fd(void *const *buffer, int size, int fd);
backtrace函数用于获取堆栈的地址信息,backtrace_symbols函数把堆栈地址翻译成我们易识别的字符串, backtrace_symbols_fd函数则把字符串堆栈信息输出到文件中 [2],这几个函数详细的介绍、使用和注意事项详见参考文献 [2]。
我们来简单使用下backtrace,看获取到的堆栈信息是什么样的:
#include <iostream>
#include <execinfo.h>
void test_backtrace(){
const int maxFrames = 100; // 堆栈返回地址的最大个数
void *frame[maxFrames]; // 存放堆栈返回地址
int nptrs = backtrace(frame, maxFrames);
char **strings = backtrace_symbols(frame, nptrs); // 字符串数组
if(strings == nullptr){
return;
}
for(int i = 0; i < nptrs; ++ i){
std::cout << strings[i] << '\n';
}
free(strings);
}
int main(){
test_backtrace();
return 0;
}
编译执行如下:
$ g++ -o test.out -rdynamic backtrace.cpp
$ ./test.