3. 编译与调试:使用-g选项编译、GDB启动方式、退出GDB

好,咱们正式开始动手了。

这一章,我带你走一遍最基础的流程——怎么编译出能调试的程序,怎么把GDB叫起来,以及怎么优雅地退出去。别小看这几步,我见过太多新手卡在“GDB启动后啥也不显示”这种问题上,其实就是编译时忘了加个参数。

3.1 编译时为什么要加 -g?

说白了,-g 就是告诉编译器:“嘿,把源代码和机器码的对应关系给我保留下来。”

没有 -g,你调试时看到的全是地址和汇编,根本不知道当前执行到哪一行C代码。加了 -g,GDB才能告诉你“第42行的 ptr->data 出问题了”。

核心要点:用GDB调试的程序,编译时必须加 -g 选项。

举个例子,一个最简单的程序:

// main.c
#include <stdio.h>

int main() {
    int a = 10;
    int b = 20;
    int c = a + b;
    printf("c = %d\n", c);
    return 0;
}

编译命令对比一下:

// 不带 -g,无法调试
gcc main.c -o main

// 带 -g,可以调试
gcc main.c -o main -g

我个人习惯,开发阶段一律加 -g,哪怕只是写个测试小工具。为什么?因为你永远不知道哪个角落会崩。我在项目中遇到过好几次,release版本跑得好好的,debug版本一跑就挂,最后发现是未初始化的变量在作祟。没有 -g,你连查都查不了。

小技巧:如果你用Makefile,可以把 -g 放在 CFLAGS 里,这样所有源文件都带上调试信息。

3.2 GDB的启动方式

启动GDB,其实就三种常见姿势。我按使用频率给你排个序。

方式一:直接启动,再加载程序

gdb
(gdb) file ./main
(gdb) run

这种方式适合你已经打开了GDB,想换个程序调试。我个人用得少,因为多了一步。

方式二:启动时指定程序(最常用)

gdb ./main

这是我最常用的方式。一步到位,直接进入GDB界面,等着你下断点、run。

方式三:启动时指定程序 + core文件

gdb ./main core

这个厉害了。程序崩溃后,系统会生成一个core dump文件。你用这个命令,GDB会直接定位到崩溃的那一行。我曾经靠这个救过一个线上事故——客户现场程序闪退,我远程拿到core文件,一行命令就找到了空指针的位置。

注意:如果系统没生成core文件,先执行 ulimit -c unlimited 打开core dump功能。

启动成功后,你会看到类似这样的提示:

GNU gdb (Ubuntu 12.1-0ubuntu1~22.04) 12.1
Copyright (C) 2022 Free Software Foundation, Inc.
...
Reading symbols from ./main...
(gdb)

看到 (gdb) 这个提示符,就说明你已经进入GDB的世界了。

3.3 退出GDB

退出GDB,方法也很简单。就两个常用命令:

命令 说明
quit 或 q 正常退出GDB
Ctrl + D 发送EOF信号,也会退出

我个人习惯用 q,少敲几个字母嘛。但要注意,如果你正在调试的程序还没退出,GDB会问你是否确认退出:

(gdb) q
The program is running.  Exit anyway? (y or n) y

嗯,这里要注意:如果你用 Ctrl + D,它不会问,直接退。所以如果你程序里还有没保存的数据,最好先用 kill 命令杀掉进程,再退出。

避坑指南:我曾经在调试一个网络服务时,直接用 Ctrl + D 退出了GDB,结果后台进程还在跑,端口没释放,害我排查了半天。后来我养成了习惯——退出前先 kill 一下。

3.4 本章知识体系

我把这一章的核心逻辑画成了流程图,你看一眼就明白了:

编译与调试流程 编写源代码 gcc -g 编译 启动GDB 调试(断点/单步/查看) 启动方式 1. gdb 然后 file 2. gdb ./程序 3. gdb ./程序 core 退出方式 quit / q Ctrl + D

这张图把整个流程串起来了。你记住:写代码 → 加 -g 编译 → 启动GDB → 调试 → 退出。每一步都有讲究,但核心就是那个 -g,少了它,后面全白搭。

3.5 实战小练习

光看不练假把式。你现在就可以试试:

  1. 写一个简单的 hello.c,打印一句话
  2. 用 gcc hello.c -o hello -g 编译
  3. 用 gdb ./hello 启动
  4. 在 printf 那行设个断点(下一章会细讲,先试试 break 行号)
  5. 输入 run 运行
  6. 输入 quit 退出

走完这一遍,你就已经入门了。剩下的,就是慢慢深入。

本章总结:

  • 编译加 -g,这是调试的前提
  • 启动GDB有三种方式,最常用的是 gdb ./程序
  • 退出用 quit 或 Ctrl + D,注意先杀进程

下一章,咱们聊聊断点——调试的灵魂。准备好了吗?

可可精品资料库