在 Linux 上调试 C++ 程序是一个常见的开发任务,Linux 提供了多种强大的工具来帮助你进行调试。以下是常用的调试方法和工具.
1. 使用 GDB (GNU Debugger)
GDB
是最常用且功能强大的命令行调试器,适用于 C、C++ 和其他语言。它允许你逐步执行代码、设置断点、检查变量值、查看调用栈等。
安装 GDB
大多数 Linux 发行版默认已经安装了 GDB
。如果没有,可以通过包管理器安装:
-
Debian/Ubuntu:
sudo apt-get install gdb
-
Fedora/CentOS/RHEL:
sudo dnf install gdb
-
Arch Linux:
sudo pacman -S gdb
编译带有调试信息的程序
为了使 GDB
能够提供详细的调试信息,你需要在编译时添加 -g
选项,以便生成调试符号。
g++ -g -o my_program my_program.cpp
启动 GDB
你可以通过以下方式启动 GDB
:
-
直接运行程序:
gdb ./my_program
-
附加到正在运行的进程(如果你需要调试一个已经在运行的程序):
gdb -p <pid>
常用 GDB 命令
-
run [args]
: 开始运行程序,传递参数(如果有)。(gdb) run arg1 arg2
-
break <function>
或break <file:line>
: 设置断点。(gdb) break main (gdb) break my_function (gdb) break my_file.cpp:10
-
continue
或c
: 继续执行程序,直到遇到下一个断点或异常。(gdb) continue
-
step
或s
: 单步执行,进入函数内部。(gdb) step
-
next
或n
: 单步执行,不进入函数内部。(gdb) next
-
print <expression>
或p <expression>
: 打印变量或表达式的值。(gdb) print x (gdb) print my_object->get_value()
-
backtrace
或bt
: 显示当前调用栈。(gdb) backtrace
-
info locals
: 显示当前作用域中的局部变量。(gdb) info locals
-
info args
: 显示当前函数的参数。(gdb) info args
-
watch <expression>
: 设置监视点,当表达式的值发生变化时暂停程序。(gdb) watch x
-
delete <breakpoint-number>
: 删除指定编号的断点。(gdb) delete 1
-
quit
或q
: 退出 GDB。(gdb) quit
示例:调试一个简单的 C++ 程序
假设你有一个简单的 C++ 程序 main.cpp
:
#include <iostream>
void foo() {
int a = 5;
int b = 0;
int c = a / b; // 这里会触发除零错误
}
int main() {
foo();
std::cout << "Program finished." << std::endl;
return 0;
}
-
编译程序:
g++ -g -o my_program main.cpp
-
启动 GDB:
gdb ./my_program
-
设置断点并运行程序:
(gdb) break foo (gdb) run
-
单步执行:
(gdb) step
-
查看变量值:
(gdb) print a (gdb) print b
-
继续执行,直到遇到除零错误:
(gdb) continue
-
查看调用栈:
(gdb) backtrace
2. 使用 Visual Studio Code (VSCode) 调试
VSCode 提供了一个图形化的调试界面,结合 GDB 或 LLDB,可以更方便地调试 C++ 程序。以下是如何在 VSCode 中配置和使用调试器的步骤。
安装必要的扩展
-
安装 C/C++ 扩展:
- 打开 VSCode。
- 点击左侧活动栏中的扩展图标(四个方块组成的图标)。
- 搜索并安装
C/C++
扩展(由 Microsoft 提供)。
-
安装调试器:
- 对于 GDB,确保系统上已经安装了
gdb
。 - 对于 LLDB,确保系统上已经安装了
lldb
。
- 对于 GDB,确保系统上已经安装了
配置 launch.json
在项目的根目录下创建 .vscode
文件夹,并在其中创建 launch.json
文件。这个文件用于配置调试器的启动参数。
{
"version": "0.2.0",
"configurations": [
{
"name": "(gdb) Launch",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/my_program", // 你的可执行文件路径
"args": [], // 传递给程序的参数
"stopAtEntry": false, // 是否在程序入口处停止
"cwd": "${workspaceFolder}", // 工作目录
"environment": [],
"externalConsole": false, // 是否在外部终端中运行
"MIMode": "gdb", // 使用的调试器 (gdb 或 lldb)
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "-enable-pretty-printing",
"ignoreFailures": true
}
],
"preLaunchTask": "build", // 可选:在调试前运行的任务(如编译)
"miDebuggerPath": "/usr/bin/gdb", // GDB 的路径
"internalConsoleOptions": "neverOpen"
}
]
}
创建 tasks.json
如果你希望在调试前自动编译程序,可以在 .vscode
文件夹中创建 tasks.json
文件,定义编译任务。
{
"version": "2.0.0",
"tasks": [
{
"label": "build",
"type": "shell",
"command": "g++",
"args": [
"-g",
"-o",
"${workspaceFolder}/my_program",
"${workspaceFolder}/main.cpp"
],
"group": {
"kind": "build",
"isDefault": true
},
"problemMatcher": ["$gcc"],
"detail": "Generated task to build the program."
}
]
}
启动调试
- 打开 VSCode。
- 点击左侧活动栏中的“运行和调试”图标(通常是一个虫子图标)。
- 选择你刚刚配置的调试配置(例如
(gdb) Launch
)。 - 点击绿色的“开始调试”按钮,或者按
F5
。
3. 使用 LLDB
LLDB
是另一个强大的调试器,最初为 macOS 设计,但现在也广泛支持 Linux。它的命令语法与 GDB
类似,但有一些差异。
安装 LLDB
-
Debian/Ubuntu:
sudo apt-get install lldb
-
Fedora/CentOS/RHEL:
sudo dnf install lldb
-
Arch Linux:
sudo pacman -S lldb
启动 LLDB
lldb ./my_program
常用 LLDB 命令
-
run [args]
: 开始运行程序,传递参数(如果有)。(lldb) run arg1 arg2
-
breakpoint set -n <function>
或breakpoint set -f <file> -l <line>
: 设置断点。(lldb) breakpoint set -n main (lldb) breakpoint set -f my_file.cpp -l 10
-
continue
或c
: 继续执行程序,直到遇到下一个断点或异常。(lldb) continue
-
step
或s
: 单步执行,进入函数内部。(lldb) step
-
next
或n
: 单步执行,不进入函数内部。(lldb) next
-
print <expression>
或p <expression>
: 打印变量或表达式的值。(lldb) print x (lldb) print my_object->get_value()
-
thread backtrace
或bt
: 显示当前调用栈。(lldb) thread backtrace
-
frame variable
: 显示当前帧中的变量。(lldb) frame variable
-
quit
或q
: 退出 LLDB。(lldb) quit
4. 使用 Valgrind 检查内存问题
Valgrind
是一个非常有用的工具,专门用于检测内存泄漏、非法内存访问等问题。虽然它不是调试器,但它可以帮助你发现潜在的内存问题。
安装 Valgrind
-
Debian/Ubuntu:
sudo apt-get install valgrind
-
Fedora/CentOS/RHEL:
sudo dnf install valgrind
-
Arch Linux:
sudo pacman -S valgrind
使用 Valgrind
valgrind --leak-check=full ./my_program
Valgrind
会运行你的程序,并在程序结束时输出详细的内存分析报告。你可以根据报告中的提示修复内存泄漏或其他问题。
5. 使用 AddressSanitizer (ASan) 检测内存错误
AddressSanitizer
是一个编译器内置的工具,专门用于检测内存错误,如越界访问、未初始化内存访问等。它比 Valgrind
更快,因为它是在编译时插入检查代码的。
编译时启用 ASan
g++ -fsanitize=address -g -o my_program my_program.cpp
运行程序
./my_program
如果程序中有内存错误,AddressSanitizer
会在运行时输出详细的错误信息。
6. 使用 GProf 分析性能
GProf
是一个简单的性能分析工具,可以帮助你了解程序的性能瓶颈。它通过记录函数调用的时间和频率来生成性能报告。
编译时启用 GProf
g++ -pg -o my_program my_program.cpp
运行程序
./my_program
程序运行后会生成一个名为 gmon.out
的文件,包含性能数据。
生成报告
gprof ./my_program gmon.out > profile.txt
你可以查看 profile.txt
文件,了解哪些函数消耗了最多的时间。
总结
在 Linux 上调试 C++ 程序有多种工具和方法可供选择,具体取决于你的需求:
- GDB 是最常用的调试器,适合大多数调试场景。
- VSCode 提供了图形化的调试界面,结合 GDB 或 LLDB,适合喜欢图形化工具的开发者。
- LLDB 是另一个强大的调试器,尤其适合 macOS 和现代 Linux 系统。
- Valgrind 和 AddressSanitizer 专注于内存问题的检测,帮助你发现潜在的内存泄漏和非法访问。
- GProf 用于性能分析,帮助你优化程序的性能。