Linux 编辑、编译与调试:Vim、GCC 与 GDB
本节学习 Linux 环境下完整的代码开发流程:使用 Vim 创建和编辑源文件,使用 GCC 编译单文件或多文件程序,再通过 GDB 进行源码级调试。
重点包括 Vim 的三种工作模式和常用操作、GCC 的输出文件、头文件搜索路径与宏定义选项,以及 GDB 的单步执行、变量观察和断点管理。
一、Vim 编辑器
1.1 Vim 的作用
使用 vi 命令进入 Vim:
vi 文件名它有两种常见情况:
- 文件已经存在:打开并编辑该文件;
- 文件不存在:先进入一个新的空缓冲区,保存后才会真正创建文件。
例如:
vi aa如果 aa 原本不存在:
- 使用
:wq保存退出后,磁盘上会出现aa; - 使用
:q!不保存退出后,aa不会被创建。
1.2 Vim 的三种工作模式
Vim 的操作关键在于先判断当前处于哪一种模式。
| 模式 | 作用 | 进入方式 |
|---|---|---|
| 命令模式(普通模式) | 删除、复制、粘贴、撤销、查找等 | 打开 Vim 后默认进入;插入模式下按 Esc 返回 |
| 插入模式 | 输入和修改文件内容 | 命令模式下按小写 i |
| 末行模式 | 保存、退出、分屏等 | 命令模式下按 : |
1.3 保存与退出
| 命令 | 含义 | 适用情况 |
|---|---|---|
:wq | 保存并退出 | 内容需要保留 |
:q! | 强制退出,不保存修改 | 放弃本次修改 |
:q | 直接退出 | 文件没有发生修改时 |
其中:
w表示 write(写入、保存);q表示 quit(退出);!表示强制执行。
即使先输入了一些内容,后来又手动删回原样,Vim 仍可能认为文件被修改过。此时 :q 不能退出,需要使用 :wq 或 :q!。
1.4 命令模式下的常用操作
1.4.1 删除行
dd删除光标当前所在的一行。
Ndd从光标所在行开始,向下删除 N 行。
示例:
5dd表示从当前行开始向下删除 5 行。
1.4.2 撤销与反撤销
| 命令 | 作用 |
|---|---|
u | 撤销上一步操作,连续按可逐步向前撤销 |
U | 一次性撤销当前行此前所做的修改 |
Ctrl+R | 反撤销,即恢复刚刚撤销的操作 |
1.4.3 复制与粘贴
yy复制当前行。
Nyy从当前行开始向下复制 N 行。
示例:
5yy表示复制从当前行开始的 5 行。
复制后,把光标移动到目标位置,再按:
p内容会粘贴到光标所在行的下一行。
1.4.4 查找字符串
/字符串输入后按回车,Vim 会查找并高亮匹配内容。
n跳到下一个匹配位置。查找到文件末尾后,会从文件开头继续循环查找。
1.4.5 查看函数帮助
先把光标移动到函数名上,再执行:
| 命令 | 作用 |
|---|---|
K | 按默认手册章节查看帮助 |
2K | 查看第 2 章系统调用手册 |
3K | 查看第 3 章库函数手册 |
进入帮助页面后,按 q 退出帮助。
1.4.6 整体格式化代码
gg=G按键含义:
gg:移动到文件开头;=:执行缩进格式化;G:范围到文件结尾。
1.5 Vim 分屏
实际项目通常包含多个源文件和头文件。分屏可以在同一个 Vim 会话中同时查看或编辑多个文件。
1.5.1 左右分屏
:vsp 文件名1.5.2 上下分屏
:sp 文件名1.5.3 在多个窗口之间切换
Ctrl+W,然后再按 W1.5.4 分屏中的保存和退出
光标当前位于哪个窗口,插入、保存和退出命令就作用于哪个文件。
二、GCC 编译
2.1 从源文件生成可执行文件
gcc 源文件 -o 目标文件例如:
gcc main.c -o myapp含义:
gcc:调用 GCC 编译器;main.c:要编译的源文件;-o myapp:把输出文件命名为myapp。
运行当前目录中的程序:
./myappLinux 不会默认到当前目录查找程序,所以运行当前目录中的可执行文件时要写 ./。
2.2 不指定输出文件名
如果只写:
gcc main.cGCC 会生成默认名称:
a.out2.3 查看 GCC 版本
gcc -v2.4 编译多个源文件
当一个项目由多个 .c 文件组成时,需要把参与编译的源文件全部列出。
进入 src 目录后,可编译多个源文件:
gcc main.c add.c mul.c -I../include -o myapp2.5 使用 -I 指定头文件搜索路径
如果头文件与源文件不在同一目录,编译器默认可能找不到头文件,需要使用大写 -I 指定头文件目录:
-I头文件目录示例:
-I../include2.6 使用 -Wall 显示更多警告
gcc main.c -Wall -o myapp2.7 使用 -D 在编译时定义宏
示例:
int a = 0;
#ifdef DEBUG a += 100;#else a += 200;#endif不定义 DEBUG 宏时:
gcc main.c -o myapp程序进入 #else 分支,a 的结果为 200。
在编译时定义 DEBUG 宏:
gcc main.c -DDEBUG -o myapp程序进入 #ifdef DEBUG 分支,a 的结果为 100。
三、GDB 调试
3.1 为什么编译时要加 -g
若想进行源码级调试,编译时要加入小写 -g:
gcc -g qwpj.c -o qwpj23.2 进入 GDB
gdb 可执行文件名例如:
gdb qwpj23.3 查看源代码:list
缩写:
l作用:在 GDB 中显示源代码,一次显示大约 10 行。
还可以指定行号:
l 1l 23用于查看指定行附近的源代码。如果行号超出源码范围,GDB 会给出范围提示。
3.4 开始调试:start 与 run
start
start从头开始调试,并默认停在 main 函数的第一条可执行语句处。
GDB 当前显示的代码行表示“下一条即将执行的语句”,不是“已经执行完的语句”。
run
缩写:
r作用:从程序开头运行。
- 有断点:停在遇到的第一个断点处;
- 没有断点:直接运行到程序结束。
对比:
| 命令 | 开始后停在哪里 |
|---|---|
start | 默认停在 main 的第一条可执行语句 |
run / r | 停在第一个断点;没有断点则运行到结束 |
3.5 单步调试:step 与 next
单步进入函数
缩写:
s如果当前语句调用了函数,step 会进入该函数内部继续调试。
单步越过函数
缩写:
n如果当前语句调用了函数,next 会把函数调用作为一整步执行,不进入函数内部,然后停在下一行。
对比:
| 命令 | 遇到函数调用时 |
|---|---|
step / s | 进入函数内部 |
next / n | 不进入函数,执行后停在下一行 |
3.6 查看变量
单次打印变量
print 变量名缩写:
p 变量名它只打印变量当前这一刻的值。
持续显示变量
display 变量名之后每执行一步,GDB 都会自动显示该变量的新值。
可以同时 display 多个变量,GDB 会为每个持续显示项分配编号。
取消持续显示
undisplay 编号例如:
undisplay 2注意:undisplay 后面写的是显示项编号,不是变量名。
3.7 设置断点
GDB 可以按行号或函数名设置断点。
按行号设置断点
break 9缩写:
b 9按函数名设置断点
break 函数名缩写:
b 函数名3.8 查看断点信息
info breakpoints3.9 继续运行到下一个断点
continue缩写:
c3.10 禁用与重新启用断点
禁用断点:
disable 断点编号重新启用断点:
enable 断点编号3.11 退出 GDB
quit缩写:
q如果这篇文章对你有帮助,欢迎分享给更多人!





