与Windows下C开发相比,Linux下C开发最大的困难就是程序的调试。

Windows下,Visual Studio系列的IDE(Visual Studio 2010/2013/2015/2017/2019/2022)都内置了C++调试引擎,可通过可视化的界面完成调试操作:在IDE里设置调试断点,然后按F5就可以开始调试了,简单又方便。而且功能强大,支持 断点调试、变量查看、单步执行、堆栈跟踪等等。

Linux就没有这么幸运了,没有这么强大可用的可视化工具。Linux下C++的调试,主要又两种方式:

  • 日志打印: 在代码中通过log打印相关的调试信息,程序运行后分享log的数据进行调试。如果你是开发阶段,或者你的程序是一个简单的Demo,也可以直接用std::cout(C++)或printf(C语言)来打印调试信息。
  • GDB调试: GDB是GNU DeBug的缩写,是Linux的调试器。你需要了解GDB工具的常见用法和调试手段。

本文将带领大家一起入门Linux下GDB的调试方法。

1. GDB的介绍

1.1. 什么是GDB?

GDB的全称是GNU DeBugger,它是一个由GNU项目开发的开源调试器,用于调试C和C++程序。GDB允许开发者检查程序的执行过程,设置断点,查看变量值,以及执行其他调试任务,如分析程序崩溃的原因。

GDB支持多种编程语言,包括C、C++、Objective-C、Fortran、Pascal等。通过GDB,开发者可以更有效地诊断和修复代码中的错误,提高开发效率。

1.2. 安装GDB

 Linux C++ 开发1 - 搭建C++开发环境》一文,我们介绍了Linux C++开发环境的搭建,其中包括了安装GDB的步骤。如果你的系统(Ubuntu)还未安装gdb,可以通过以下命令来安装:

# 安装gdb
sudo apt install gdb
# 检查gdb是否安装成功
gdb --version
  • 1.
  • 2.
  • 3.
  • 4.

2. 编译带调试信息的程序

为了能使用GDB进行调试,需要在编译时包含调试信息(即在编译时能够生成调试符号表symbols)。使用-g-ggdb选项进行编译:

2.1. 命令行编译

# -g选项:生成标准的调试信息
g++ -g -o my_program my_program.cpp
# -ggdb选项:生成gdb专用的调试信息
g++ -ggdb -o my_program my_program.cpp
  • 1.
  • 2.
  • 3.
  • 4.
  • -g 选项用于生成标准的调试信息,这些信息可以被多种调试器使用,该选项生成的调试信息符合DWARF(Debugging With Attributed Record Formats)标准,DWARF这是一种通用的调试信息格式。
  • -ggdb 选项专门为GDB生成调试信息。它生成的调试信息可能包含一些GDB特有的扩展,这些扩展可能不适用于其他调试器,不过使用-ggdb选项可以确保生成的调试信息对GDB是最优的。

2.2. makefile编译

# 构建的最终目标 Iterator(可执行文件)
Iterator:Iterator.o Company.o Person.o
 g++ -o Iterator Iterator.o Company.o Person.o
# 构建目标 Iterator.o
Iterator.o:Iterator.cpp
 g++ -g -c Iterator.cpp
# 构建目标 Company.o
Company.o:Company.cpp
 g++ -g -c Company.cpp
# 构建目标 Person.o
Person.o:Person.cpp
 g++ -g -c Person.cpp

# 申明clean为伪目标
.PHONY: clean
clean:
 rm -f *.o Iterator
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.

注意:

2.3. cmake编译

# 设置构建类型: Debug/Release
set(CMAKE_BUILD_TYPE Debug)
# 设置编译选项
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
    # Debug模式,编译是需要保留调试符号表
    set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -g")
elseif(CMAKE_BUILD_TYPE STREQUAL "Release")
    # Release模式,编译时优化代码,优化选项:-O2
    set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O2")
endif()
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.

3. GDB使用流程

3.1. 测试源代码准备

demo02.cpp:

#include <iostream>

int add(int a, int b)
{
    return a + b;
}

int division(int a, int b)
{
    return (int)(a / b);
}

int main()
{
    std::string name = "Spencer";
    std::cout << "Hello, " << name << "!" << std::endl;
    int a = 5;
    int b = 0;
    int c = division(a, b);
    int d = add(c, 20);
    std::cout << "d = " << d << std::endl;
    return 0;
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.

Iterator:

参见源码仓库:  https://gitee.com/spencer_luo/iterator/tree/cmake/

3.2. 启动GDB

使用以下命令启动GDB并加载要调试的程序:

# 正常启动,program_name为带符号表的可执行程序
gdb program_name
# quiet, 表示不打印gdb版本等信息,界面较为干净;
gdb -q program_name
  • 1.
  • 2.
  • 3.
  • 4.

测试如下:

gdb ./demo02.out 
GNU gdb (Ubuntu 15.0.50.20240403-0ubuntu1) 15.0.50.20240403-git
Copyright (C) 2024 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<https://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
    <http://www.gnu.org/software/gdb/documentation/>.
    <http://www.gnu.org/software/gdb/documentation/>.

--Type <RET> for more, q to quit, c to continue without paging--
    <http://www.gnu.org/software/gdb/documentation/>.

--Type <RET> for more, q to quit, c to continue without paging--
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from ./demo02.out...
    <http://www.gnu.org/software/gdb/documentation/>.

    <http://www.gnu.org/software/gdb/documentation/>.
    <http://www.gnu.org/software/gdb/documentation/>.

--Type <RET> for more, q to quit, c to continue without paging--

--Type <RET> for more, q to quit, c to continue without paging--
--Type <RET> for more, q to quit, c to continue without paging--
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from ./demo02.out...
(gdb)
(gdb) q
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
gdb -q ./demo02.out
Reading symbols from ./demo02.out...
(gdb)
(gdb) q
  • 1.
  • 2.
  • 3.
  • 4.

3.3. 查看源码

list(缩写l): 查看源程序代码,默认显示10行,按回车键继续看余下的。

Linux C++ 开发6 - GDB调试入门指南_开发工具

3.4. 运行程序

run(缩写r) :运行程序直到遇到 结束或者遇到断点等待下一个命令。

Linux C++ 开发6 - GDB调试入门指南_开发工具_02

我们直接运行./demo02.out看到程序崩溃了,但是不知道崩溃在哪一行。但是通过gdb一运行,立马就看出来了。

3.5. 设置断点

break n(缩写b n) :在第n行设置断点。

Linux C++ 开发6 - GDB调试入门指南_开发工具_03

3.6. 单步执行

使用 continue、step、next命令。

3.7. 查看变量

使用 print、info locals命令。

Linux C++ 开发6 - GDB调试入门指南_开发工具_04

4. GDB常用命令

更多GDB常用命令,将在下一节进行讲解,敬请期待…


大家好,我是陌尘。

IT从业10年+, 北漂过也深漂过,目前暂定居于杭州,未来不知还会飘向何方。

搞了8年C++,也干过2年前端;用Python写过书,也玩过一点PHP,未来还会折腾更多东西,不死不休。

感谢大家的关注,期待与你一起成长。


【SunLogging】

Linux C++ 开发6 - GDB调试入门指南_开发工具_05

扫码二维码,关注微信公众号,阅读更多精彩内容