
往期《Linux系统编程》回顾:/------------ 入门基础 ------------/ 【Linux的前世今生】 【Linux的环境搭建】 【Linux基础 理论+命令】(上) 【Linux基础 理论+命令】(下) 【权限管理】 /------------ 开发工具 ------------/ 【软件包管理器 + 代码编辑器】 【编译器 + 自动化构建器】
hi~ 小伙伴们大家好呀!(ノ≧∀≦)ノ 之前鼠鼠带大家学了 【软件包管理器 + 代码编辑器】、【编译器 + 自动化构建器】,本来以为大家都已经写出优雅代码,让程序在云服务器上稳稳跑起来了呢~٩(ˊᗜˋ*)و 结果居然有小可爱说,写的时候踩了 bug,程序到现在还没成功运行?┻━┻︵ ╰(‵□′)╯︵ ┻━┻ 嘤嘤嘤 (╥﹏╥),别慌别慌,鼠鼠这就带着 “救星工具” 来帮你! (。•̀ᴗ-)✧
今天咱们要学的核心内容就是 【版本控制器 + 调试器】!( ̄︶ ̄)↗
版本控制器:能帮你追踪代码修改、回溯历史版本,不怕改崩代码找不回原样调试器:则是找 bug 的 “火眼金睛”,能一步步排查问题、定位错误根源有了这俩 “神器”,搞定 bug、稳妥管理代码都不是事儿,赶紧一起解锁新技能吧~(っ´▽`)っ♡
git:是一个 开源的分布式版本控制系统(Distributed Version Control System,简称 DVCS),由 Linux 内核创始人 Linus Torvalds 于 2005 年开发,最初目的是解决 Linux 内核开发中 “多人协作、代码版本追踪、历史回溯” 的需求。
前世:BitKeeper 的使用与授权风波
今生:Git 的诞生与发展
速度快、设计简单、支持非线性开发、完全分布式以及能高效处理大型项目等目标一个生动的比喻:打游戏存档 想象你在玩一个很难的角色扮演游戏(RPG):
在这个比喻里:
git 解决的三大核心问题:
总结: 不管是个人开发还是团队协作,git 都能解决很多实际痛点:
功能 | 没有 git 的世界 | 有 git 的世界 |
|---|---|---|
备份 | 手动复制文件夹,混乱且容易丢 | 自动记录每次更改,随时回退 |
协作 | 文件传来传去,合并靠人工 | 自动合并,冲突清晰标识 |
历史 | 靠注释和记忆 | 完整记录,责任清晰 |
试验 | 不敢轻易尝试,怕改不回来 | 开分支随意试验,失败即删 |
所以:git 是现代软件开发中不可或缺的基础工具,它让个人开发和团队协作变得高效、安全、有条不紊。无论是程序员、作家(虽然没那么常用),还是任何需要管理文本文件历史的人,都能从 git 中受益。
git 的核心特点:
点击进入GitHub官网:GitHub






需要按照以下步骤生成 SSH 密钥,并将公钥添加到 GitHub 账号中:
步骤 1:生成 SSH 密钥对
在本地终端执行以下命令(替换成你自己的 GitHub 绑定邮箱):
ssh-keygen -t rsa -b 4096 -C "你的GitHub邮箱@example.com"执行后会有一系列提示,一路按回车即可(默认将密钥保存在 ~/.ssh/ 目录下,文件名为 id_rsa(私钥)和 id_rsa.pub(公钥))

步骤 2:将公钥添加到 GitHub 账号
cat ~/.ssh/id_rsa.pub,会输出一长串以 ssh-rsa 开头的文本,复制这段文本
注意:并不是点击完“Add SSH Key”按钮,就是已经将公钥添加到 GitHub 账号上了,还需要输入密码进行“Confirm access”确认访问。


步骤 3:测试 SSH 连接
执行以下命令,测试能否正常连接到 GitHub:
ssh -T git@github.comHi sanqiuDev! You've successfully authenticated, but GitHub does not provide shell access. 的提示,说明 SSH 连接配置成功步骤 4:克隆仓库
现在执行克隆命令:
git clone 你的githum仓库的ssh链接git add(添加文件到暂存区)
git add 文件名 # 添加单个文件,例如 git add code.c
git add . # 添加当前目录下所有 新增/修改 的文件这个命令的作用是告诉 Git:“这些文件我要纳入版本管理啦”,把文件从工作区添加到暂存区(临时存储改动的地方),方便后续提交。
git commit(提交到本地仓库)
git commit -m "这里写提交说明" # 例如 git commit -m "修复登录功能的bug"这一步会把暂存区的所有改动正式提交到本地仓库,形成一个版本记录。
双引号里的文字要简洁清晰地描述这次改了什么(比如:新增功能、修复 bug 等),方便以后回溯历史时快速理解。
git push(推送到远程仓库)
git push # 推送到默认的远程仓库和分支
# 首次推送可能需要指定分支,例如:git push -u origin main执行后,本地仓库的提交记录会被上传到远程仓库,这样团队成员或其他设备就能获取到你的最新代码了。
总结:这三个命令是 Git 日常操作的核心流程,先标记要管理的文件,再保存到本地仓库,最后同步到远程服务器,确保代码安全和协作顺畅~


点击进入Gitee官网:Gitee - 基于 Git 的代码托管和研发协作平台




如果你的 Windows 系统还没有安装 Git,需要先下载并安装 Git for Windows 安装过程中保持默认设置即可,安装完成后,确保 Git 已经添加到系统环境变量中。
打开 Windows PowerShell,执行以下命令配置你的 Git 用户名和邮箱:
git config --global user.name "你的用户名"
git config --global user.email "你的邮箱@example.com""你的用户名" 和 "你的邮箱@example.com" 替换为你在 Gitee 上注册的用户名和邮箱
在 PowerShell 中,使用 git clone 命令克隆 Gitee 上的仓库。
git clone 仓库的HTTPS链接linux-study 的文件夹,并将仓库内容下载到该文件夹中

使用 cd 命令进入克隆好的仓库目录:
cd linux-study




在软件开发中,
Debug(调试)和Release(发布)是两种常见的构建模式,它们服务于不同的目的,在编译选项、代码优化、可执行文件特性等方面存在显著差异。
1. Debug(调试模式) 核心目的:用于开发和调试阶段,方便开发者查找、修复代码中的错误。(如:逻辑错误、崩溃、内存泄漏等) 关键特点
2. Release(发布模式) 核心目的:用于最终发布给用户的版本,确保程序在用户环境中高效、稳定运行。 关键特点
总结对比:
维度 | Debug 模式 | Release 模式 |
|---|---|---|
用途 | 开发、调试阶段 | 发布给用户的最终版本 |
调试信息 | 包含完整调试信息 | 无调试信息 |
代码优化 | 关闭或极少优化 | 开启全量优化 |
可执行文件大小 | 较大 | 较小 |
运行速度 | 较慢 | 较快 |
简单来说:Debug 是 “方便开发者找问题” 的版本,Release 是 “让用户高效使用” 的版本。
在 Linux 系统中,使用 gcc 或 g++ 编译程序时,默认采用的是类似 Release 的模式 —— 生成的可执行文件经过一定优化,且不包含调试信息。
因此:Linux 下用默认方式编译的程序无法直接调试。
疑问:那我们要怎么切换到 Debug 模式呢?
若要切换到 Debug 模式,只需在编译时添加 -g 选项即可,例如:
# 以 Debug 模式编译单个源文件
gcc main.c -o program -g
# 以 Debug 模式编译多个源文件
gcc main.c process.c -o program -g-g 选项后,编译器会在生成的可执行文件中嵌入调试信息,此时就能用 gdb 等工具进行调试了(如:gdb ./program)
readelf -S code1/code2 | grep -i debug:用于查看可执行文件code1/code2中与调试(debug)相关的段(section)信息,帮助判断程序是否包含调试符号(即是否以支持调试的方式编译)
命令拆解
readelf -S code1/code2:执行后会列出 code1/code2 所有段的详细信息
readelf:是 Linux 下的工具,用于查看 ELF 格式文件(可执行文件、库文件等)的信息
-S:选项表示查看文件的 段(Section) 信息(段是 ELF 文件中承载不同类型数据的单元,比如:代码段、数据段、调试信息段等)
| grep -i debug:
|:是管道符,将前一个命令(readelf -S processbar)的输出传递给后一个命令(grep)
grep:用于在文本中筛选匹配的内容
-i:选项表示忽略大小写,debug 是要匹配的关键词(筛选与调试相关的段)
实际效果
gcc -g 编译,包含调试符号),执行该命令会输出包含 debug 的段信息(例如:.debug_info、.debug_line 等调试相关段)-g 选项,无调试符号),执行该命令可能没有输出,或只有极少与调试无关的零星匹配(说明程序几乎不含调试信息)简单来说:这条命令是用来快速验证可执行文件是否包含调试符号的 “探针”~
1. 快速认识使用 gdb
gdb 可执行文件(比如:gdb bin)启动 gdb 并加载待调试的可执行文件
quit 命令即可退出 gdb 调试环境

2. 掌握基础调试命令
另外,在 gdb 不退出的情况下,多次设置断点,断点编号会依次递增,方便管理多个断点。
命令 | 作用 | 样例 |
|---|---|---|
list/l | 显示源代码,从上次位置开始,每次列出 10 行 | list/l 10 |
list/l 函数名 | 列出指定函数的源代码 | list/l main |
list/l 文件名:行号 | 列出指定文件的源代码 | list/l mycmd.c:1 |
命令 | 作用 | 样例 |
|---|---|---|
break/b [文件名:]行号 | 在指定行号设置断点 | break 10 break test.c:10 |
break/b 函数名 | 在函数开头设置断点 | break main |
info break/b | 查看当前所有断点的信息 | info break |
命令 | 作用 | 样例 |
|---|---|---|
r/run | 从程序开始连续执行 | run |
continue/c | 从当前位置开始连续执行程序 | continue |
n/next | 单步执行,不进入函数内部,逐过程(类似 F10) | next |
s/step | 单步执行,进入函数内部,逐语句(类似 F11) | step |


我们可以借助 cgdb 来改善 gdb 的使用体验,cgdb能让代码和调试信息同时展示,为 gdb 提供更友好的界面,方便调试时查看代码:
sudo yum install -y cgdb 来安装 cgdbsudo apt install -y cgdb 安装 cgdb温馨提示:使用gdb/cgdb进行调试时候,指定调试的可执行程序一定要是使用
-g编译生成的,不然的话,无法显示要调试的代码。

简单的了解一下cgdb的分屏切换操作:

学会简单的使用cgdb的分屏界面切换后,接下来我们就来学习怎么在cgdb中进行调试啦。 这里先说明一下,我们使用的调试代码是:
// mycmd.c
#include <stdio.h>
int flag = 0; //故意错误
int Sum(int s, int e)
{
int result = 0;
for (int i = s; i <= e; i++)
{
result += i;
}
//return result;
return result * flag; //故意错误
}
int main()
{
int start = 1;
int end = 100;
printf("I will begin\n");
int n = Sum(start, end);
printf("running done, result is: [%d-%d]=%d\n", start, end, n);
return 0;
}命令 | 作用 | 样例 |
|---|---|---|
p 变量 | 打印指定变量的值 | p x |
finish | 执行到当前函数返回然后停止 | finish |
backtrace/bt | 查看当前执行栈的各级函数调用及参数 | backtrace |


在 gdb 中使用
info break(或info breakpoints)命令查看断点信息时,输出的每一列都有其特定含义,下面来逐一解释: Num(断点编号):这一列显示的是断点的编号,是 gdb 为每个断点分配的唯一标识。
1,说明当前只有一个断点,编号为 1delete 断点编号)、禁用(disable 断点编号)或启用(enable 断点编号)等Type(断点类型):表示断点的类型,示例中是 breakpoint,即普通的软件断点。
breakpoint 是最常用的,用于在指定的代码位置暂停程序执行Disp(断点处置方式):说明当断点被命中后,该断点的状态变化。
keep,意味着断点被命中后,仍然会保留,下次程序执行到该位置时,还会在此处暂停delete(断点被命中后自动删除,仅生效一次)等Enb(断点启用状态):显示断点是否处于启用状态。
y(yes 的缩写),表示该断点是启用的,程序执行到此处会暂停n(no 的缩写),则表示断点被禁用,不会产生暂停效果Address(断点地址):显示断点所在的内存地址。
0x000000000001c3 这样的十六进制地址,它对应着程序代码在内存中的具体位置,帮助我们从底层了解断点的位置What(断点相关信息):这一列包含了断点的具体位置等详细信息。
in main at mycmd.c:29,意思是这个断点设置在 mycmd.c 文件中 main 函数里的第 29 行,明确了断点在代码层面的位置,方便我们快速定位到对应的代码处 通过 info break 命令输出的这些信息,我们可以全面了解当前所有断点的状态、位置等情况,从而更好地管理和使用断点进行调试工作。
命令 | 作用 | 样例 |
|---|---|---|
delete/d break | 删除所有断点 | delete break |
delete/d n | 删除序号为 n 的断点 | delete 1 |
命令 | 作用 | 样例 |
|---|---|---|
disable break | 禁用所有断点 | disable break |
disable n | 禁用序号为 n 的断点 | disable 1 |
enable break | 启用所有断点 | enable break |
enable n | 启用序号为 n 的断点 | enable 1 |

疑问:我们知道使用VS进行调试有一个非常好用的功能就是:“监视”,那么我们应该怎么使用cgdb进行监视呢?
命令 | 作用 | 样例 |
|---|---|---|
display 变量名 | 跟踪显示指定变量的值(每次停止时) | display x |
info/i locals | 查看当前栈帧的局部变量值 | info locals |
undisplay 编号 | 取消对指定编号的变量的跟踪显示 | undisplay 1 |
until 行号 | 执行到指定行号 | until 20 |
命令 | 作用 | 样例 |
|---|---|---|
print/p 表达式 | 打印表达式的值 | print start+end |

watch命令:变量与表达式监控 watch 命令的核心作用是:在程序执行过程中,持续监视一个表达式(比如:变量、算术表达式等)的值
使用场景
watch 命令监视它注意事项
watch 不仅能监视单个变量,还能监视更复杂的表达式(如:a + b、ptr->value 等),只要表达式的值发生变化,就会触发暂停
set var:修改变量以定位问题 set var 命令的作用是:在调试过程中,手动修改程序中变量的值
使用场景
flag,我们怀疑代码逻辑在 flag 为某一特定值时会出错set var flag = 1(假设目标值为 1)修改标志位,然后继续执行程序,观察是否会出现预期的问题,以此来验证问题是否由该变量的取值导致
调试的本质可以概括为以下几个关键环节:
而断点在调试中有着重要作用:它的本质是对代码进行块级别的划分,能够以代码块为单位,帮助我们快速定位到可能存在问题的代码区域。 此外,还有一些调试命令也很实用:
finish 命令:可以用于确认问题是否出在当前正在执行的函数内部until 命令:能够实现局部区域代码的快速执行,方便我们跳过一些无需逐行调试的代码段
