C++ debug
在 C++ 中,查看程序的调用栈(Call Stack)通常用于调试崩溃、性能问题或逻辑错误等场景。以下是几种常用的方法来查看调用栈:
1. 使用 GDB 调试器查看调用栈
GDB(GNU Debugger)是 Linux 上非常流行的调试工具,可以用来查看 C++ 程序的调用栈。
示例:
假设有以下 C++ 程序:
#include <iostream>void func_c() {throw std::runtime_error("An error occurred!");
}void func_b() {func_c();
}void func_a() {func_b();
}int main() {try {func_a();} catch (const std::exception &e) {std::cerr << e.what() << std::endl;}return 0;
}
编译程序时加入调试信息(-g 选项):
g++ -g -o my_program my_program.cpp
运行 GDB 调试:
gdb ./my_program
在 GDB 中,运行程序:
(gdb) run
当程序崩溃或异常中断时,输入以下命令查看调用栈:
(gdb) backtrace # 或简写为 bt
输出示例:
#0 func_c() at my_program.cpp:5
#1 func_b() at my_program.cpp:9
#2 func_a() at my_program.cpp:13
#3 main() at my_program.cpp:19
说明:
backtrace(或 bt)命令会显示从 main 函数到当前执行点的所有函数调用。
调用栈中的每一帧都包含函数名、文件名和行号。
2. 使用 libunwind 库
libunwind 是一个跨平台的库,支持更详细的调用栈分析。
示例:
#include <libunwind.h>
#include <iostream>void print_stacktrace() {unw_cursor_t cursor;unw_context_t context;// 初始化上下文unw_getcontext(&context);unw_init_local(&cursor, &context);std::cout << "Call stack:\n";while (unw_step(&cursor) > 0) {char func_name[256];unw_word_t offset, pc;// 获取程序计数器 (PC)unw_get_reg(&cursor, UNW_REG_IP, &pc);if (pc == 0) break;// 获取函数名if (unw_get_proc_name(&cursor, func_name, sizeof(func_name), &offset) == 0) {std::cout << "0x" << std::hex << pc << ": " << func_name << " + 0x" << offset << "\n";} else {std::cout << "0x" << std::hex << pc << ": [unknown]\n";}}
}void func_c() {print_stacktrace();
}void func_b() {func_c();
}void func_a() {func_b();
}int main() {func_a();return 0;
}
编译并运行:
g++ -g -lunwind -o my_program my_program.cpp./my_program
输出示例:
Call stack:
0x4008a3: print_stacktrace + 0x3f
0x4008c3: func_c + 0x7
0x4008d3: func_b + 0x7
0x4008e3: func_a + 0x7
0x4008f3: main + 0x7
0x7f8c3f2ee0b3: __libc_start_main + 0xf3
0x4007ee: _start + 0x2e
3. 借助 IDE 调试器
现代 IDE (如 CLion、Visual Studio、VSCode)通常集成了强大的调试器,允许你在调试模式下查看调用栈。
使用方式:
在程序中设置断点。
启动调试器。
当程序暂停时,查看调用栈窗口(通常在调试面板中)。
总结
- GDB :适合在命令行下调试崩溃或运行时问题,使用 backtrace 查看调用栈。
- libunwind :功能强大,支持跨平台的调用栈分析。
- IDE 调试器 :提供图形化界面,适合实时调试。