
🔥承渊政道: 个人主页
❄️个人专栏: 《C语言基础语法知识》 《数据结构与算法》
✨逆境不吐心中苦,顺境不忘来时路! 🎬 博主简介:

引言:.在 Linux系统的开发中,对于每一位接触 Linux 编程的开发者而言,进度条看似是简单的终端交互功能,却是理解 Linux 终端输出、字符刷新、进程控制等底层逻辑的绝佳切入点 ------ 它能让你直观感受到程序的执行状态,告别 "黑盒式" 的命令行运行体验;而 Git 作为全球最主流的分布式版本控制系统,更是 Linux 生态下协作开发、代码追溯、版本回滚的 "标配工具",从单人小项目到大型开源协作,Git 都能解决代码管理的核心痛点;至于 GDB(GNU 调试器),则是 Linux 下定位程序 BUG、分析运行逻辑、调试核心崩溃的 "利器",掌握它意味着你能从 "发现错误" 进阶到 "精准定位并修复错误".本文将从实用角度出发,先拆解 Linux 终端进度条的实现逻辑,再系统介绍 Git 的核心操作与版本管理思维,最后讲解 GDB 的常用调试技巧.那么它们到底又有哪些方面的知识是需要学习和掌握的呢?废话不多说,带着这些疑问,下面跟着小编的节奏🎵一起学习吧!
目录
- 1.Linux第⼀个系统程序−进度条
- 2.版本控制器git
- 3.调试器---gdb/cgdb使⽤
-
- 3.1样例代码
- 3.2预备工作
- 3.3常⻅使⽤命令
- 3.4安装gdb/cgdb以及常⻅使用技巧
-
- 3.4.1watch
- [3.4.2set var确定问题原因](#3.4.2set var确定问题原因)
- 3.4.3添加条件断点
- 3.4.4给已经存在的断点新增条件
- 4.附录(给不同系统安装源)
1.Linux第⼀个系统程序−进度条
1️⃣进度条的概念
进度条(Progress Bar)是一种可视化交互组件 ,核心作用是将"耗时任务的执行进度"从抽象的"正在运行"转化为具象的视觉反馈------通过固定长度的视觉元素(如字符、色块)的填充比例,直观展示任务从"未开始(0%)"到"完成(100%)"的推进过程.
它并非Linux专属,广泛存在于各类软件中:
图形界面(GUI):如Windows文件拷贝的蓝色进度条、浏览器下载的进度条;
命令行界面(CLI):如Linux下wget下载文件、dd拷贝数据时的字符进度条.
2️⃣Linux命令行环境下进度条的专属特征
Linux无图形界面的命令行场景,决定了其进度条是字符型进度条 ,区别于GUI的图形进度条,核心特征如下:
①载体是终端字符:由普通ASCII字符(如#、、=)构成,而非图形色块;
②单行刷新机制:通过终端控制符(\r回车)实现"单行覆盖式更新",而非逐行输出(这是Linux进度条最核心的技术特征);
③无依赖图形库:仅依赖终端的基本I/O功能,无需GUI库(如GTK、Qt),是纯系统级的字符交互;
④进度量化核心:本质是"任务完成比例 → 字符填充长度"的数值映射(如50%进度对应50长度的进度条填充25个#).
3️⃣进度条的核心构成要素
| 要素 | 说明(以Linux字符进度条为例) |
|---|---|
| 进度量化 | 将任务进度转化为0%-100%的数值比例(核心依据) |
| 视觉映射 | 把数值比例映射为字符填充长度(如80%→40个#) |
| 实时刷新 | 按固定频率更新视觉展示(如每100ms刷新一次) |
| 状态反馈 | 附加进度数值(如80%)或提示符(如旋转的\),增强可读性 |
1.1回⻋与换⾏
回车:\r是回车(光标回到当前行开头,不换行).
换行:\n是换行(光标到下一行开头).
进度条的核心就是用\r覆盖当前行内容,而非输出新行.
1.2⾏缓冲区
缓冲区刷新fflush(stdout):
如果去掉这行,进度条会等到循环结束(100%)才一次性输出,因为printf的行缓冲特性(没遇到\n不会刷新).这是进度条能 "实时更新" 的核心.我们一起来看一下下面的例子.
bash
什么现象?
#include <stdio.h>
#include <unistd.h>
int main()
{
printf("hello world!\r\n");
sleep(3);
return 0;
}
什么现象??
#include <stdio.h>
#include <unistd.h>
int main()
{
printf("hello world!");
sleep(3);
return 0;
}
什么现象???
#include <stdio.h>
#include <unistd.h>
int main()
{
printf("hello world!");
fflush(stdout);
sleep(3);
return 0;
}
当你分别运行这三个代码时,你会发现有不同运行效果!
①hello world的后面加了\r \n会按照行进行刷新.
②hello world的后面什么都不加的,会在sleep期间,printf的函数功能就已经执行完了,屏幕上也不显示hello world的字样!那它去哪里了呢?我们肯定的是它被隐藏起来了---到内存空间里面去了!
③添加了fflush(stdout),强制刷新缓冲区,让内容实时显示(hello world).
1.3实战---倒计时程序
bash
#include <stdio.h>
#include <unistd.h>
int main()
{
int i = 10;
while(i >= 0)
{
printf("%-2d\r", i);
fflush(stdout);
i--;
sleep(1);
}
printf("\n");
return 0;
}
1.4进度条完整代码实现
Makefile代码
Makefile
BIN=process
CC=gcc
SRC=$(wildcard *.c)
OBJ=$(SRC:.c=.o)
$(BIN):$(OBJ)
$(CC) -o $@ $^
%.o:%.c
$(CC) -c $<
.PHONY:clean
clean:
rm -f $(BIN) $(OBJ)
process.c代码
c
#include "process.h"
#include <string.h>
#include <unistd.h>
#define SIZE 101
#define STYLE '='
void FlushProcess(double total, double curr) // 更新进度, 按照下载进度,进行更新进度条
{
if(curr > total)
curr = total;
double rate = curr / total * 100; // 1024.0 , 512.0 -> 0.5 -> 50.0
int cnt = (int)rate; // 50.8 , 49.9 -> 50, 49
char processbuff[SIZE];
memset(processbuff, '\0', sizeof(processbuff));
int i = 0;
for(; i < cnt; i++)
processbuff[i] = STYLE;
static const char *lable = "|/-\\";
static int index = 0;
// 刷新
printf("[%-100s][%.1lf%%][%c]\r", processbuff, rate, lable[index++]);
index %= strlen(lable);
fflush(stdout);
if(curr >= total)
{
printf("\n");
}
}
// version1: 能够使用吗??用来说明原理
void Process()
{
const char *lable = "|/-\\";
int len = strlen(lable);
char processbuff[SIZE];
memset(processbuff, '\0', sizeof(processbuff));
int cnt = 0;
while(cnt <= 100)
{
printf("[%-100s] [%d%%][%c]\r", processbuff, cnt, lable[cnt%len]);
fflush(stdout);
processbuff[cnt++] = STYLE;
usleep(30000);
}
printf("\n");
}
proces.h代码
c
#pragma once
#include <stdio.h>
// version1
void Process();
void FlushProcess(double total, double curr); // 更新进度, 按照下载进度,进行更新进度条
main.c代码
c
#include "process.h"
#include <unistd.h>
#include <time.h>
#include <stdlib.h>
double gtotal = 1024.0;
double speed = 1.0;
// 函数指针类型
typedef void (*callback_t)(double, double);
// 1.0 4.3
double SpeedFloat(double start, double range) // [1.0 3.0] -> [1.0, 4.0]
{
int int_range = (int)range;
return start + rand()%int_range + (range - int_range);
}
// cb: 回调函数
void DownLoad(int total, callback_t cb)
{
srand(time(NULL));
double curr = 0.0;
while(1)
{
if(curr > total)
{
curr = total; // 模拟下载完成
cb(total, curr); // 更新进度, 按照下载进度,进行更新进度条
break;
}
cb(total, curr); // 更新进度, 按照下载进度,进行更新进度条
curr += SpeedFloat(speed, 20.3); // 模拟下载行为
usleep(30000);
}
}
int main()
{
printf("download: 20.0MB\n");
DownLoad(20.0, FlushProcess);
printf("download: 2000.0MB\n");
DownLoad(2000.0, FlushProcess);
printf("download: 100.0MB\n");
DownLoad(100.0, FlushProcess);
printf("download: 20000.0MB\n");
DownLoad(20000.0, FlushProcess);
return 0;
}
运行效果展示
2.版本控制器git
不知道你⼯作或学习时,有没有遇到这样的情况:我们在编写各种⽂档时,为了防⽌⽂档丢失,更改失误,失误后能恢复到原来的版本,不得不复制出⼀个副本,⽐如:
"报告-v1""报告-v2""报告-v3""报告-确定版""报告-最终版""报告-究极进化版"...
每个版本有各⾃的内容,但最终会只有⼀份报告需要被我们使⽤ .但在此之前的⼯作都需要这些不同版本的报告,于是每次都是复制粘贴副本,产出的⽂件就越来越多,⽂件多不是问题,问题是:随着版本数量的不断增多,你还记得这些版本各⾃都是修改了什么吗?
⽂档如此,我们写的项⽬代码,也是存在这个问题的!!
为了能够更⽅便我们管理这些不同版本的⽂件,便有了版本控制器.所谓的版本控制器,就是能让你了解到⼀个⽂件的历史,以及它的发展过程的系统.通俗的讲就是⼀个可以记录⼯程的每⼀次改动和版本迭代的⼀个管理系统,同时也⽅便多⼈协同作业.
⽬前最主流的版本控制器就是git .git可以控制电脑上所有格式的⽂件,例如 doc、excel、dwg、dgn、rvt等等.对于开发⼈员来说,Git 最重要的就是可以帮助我们管理软件开发项⽬中的源代码⽂件!
2.1git简史
同⽣活中的许多伟⼤事物⼀样,git诞⽣于⼀个极富纷争⼤举创新的年代.
Linux 内核开源项⽬有着为数众多的参与者.绝⼤多数的 Linux 内核维护⼯作都花在了提交补丁和保
存归档的繁琐事务上(1991−2002年间).到 2002 年,整个项⽬组开始启⽤⼀个专有的分布式版本
控制系统 BitKeeper 来管理和维护代码.
到了 2005 年,开发 BitKeeper 的商业公司同 Linux 内核开源社区的合作关系结束,他们收回了 Linux
内核社区免费使⽤ BitKeeper 的权⼒.这就迫使 Linux 开源社区(特别是 Linux 的缔造者 LinusTorvalds)基于使⽤ BitKeeper 时的经验教训,开发出⾃⼰的版本系统. 他们对新的系统制订了若⼲:
⽬标:
①速度
②简单的设计
③对⾮线性开发模式的强⼒⽀持(允许成千上万个并⾏开发的分⽀)
④完全分布式
⑤有能⼒⾼效管理类似 Linux 内核⼀样的超⼤规模项⽬(速度和数据量)⾃诞⽣于 2005 年以来,git⽇臻成熟完善,在⾼度易⽤的同时,仍然保留着初期设定的⽬标.它的速度⻜快,极其适合管理⼤项⽬,有着令⼈难以置信的⾮线性分⽀管理系统.
2.2git的核心价值
git是Linus Torvalds(Linux内核创始人)为解决Linux内核开发的代码管理问题,于2005年设计的分布式版本控制系统(DVCS).它的核心作用是追踪代码文件的修改历史、管理多版本代码、支持多人协作开发,彻底解决编程中"代码改乱了回不去""多人改同一文件冲突""不知道谁改了哪行代码"等核心痛点.
git vs 传统集中式版本控制(如SVN)
| 特性 | Git(分布式) | SVN(集中式) |
|---|---|---|
| 仓库存储 | 每个人本地有完整仓库(含历史) | 只有1个中央仓库,本地无完整历史 |
| 离线操作 | 断网也能提交、回滚版本 | 必须联网才能提交 |
| 分支效率 | 分支创建/合并极快(本地操作) | 分支操作依赖中央仓库,速度慢 |
| 核心优势 | 高效、灵活、容错性强 | 结构简单,上手快 |
Git能成为Linux生态的标配,核心就是"分布式"带来的灵活性------哪怕你在离线的Linux服务器上开发,也能完整管理代码版本,联网后再同步到远程仓库(如GitHub/Gitee).
Git的核心工作区域(用"网购"比喻)
Git管理代码时,文件会处于3个核心区域,用日常网购场景比喻,更容易理解:
补充:远程仓库(如GitHub/Gitee)= 商家的"云仓库",用于多人同步代码,是本地仓库的远程副本.
| 区域 | 通俗比喻 | 核心作用 |
|---|---|---|
| 工作区(Workspace) | 你的购物桌面 | 日常编写代码的目录(比如存放进度条代码的~/progress_bar),Git默认不主动追踪这里的修改 |
| 暂存区(Staging) | 购物车 | 临时存放"准备提交的修改",相当于"标记哪些文件/修改要纳入版本管理" |
| 版本库(Repository) | 商家仓库 | Git的核心数据库(隐藏目录.git),保存所有提交的版本历史,只有提交到这里的修改才被永久记录 |
2.3安装git
bash
# Debian/Ubuntu系安装
sudo apt update && sudo apt install git -y
# CentOS/RHEL系安装
sudo yum install git -y
2.4在gitee创建项⽬
创建仓库:然后跳转到的新⻚⾯中输⼊项⽬名称(注意, 名称不能重复,系统会⾃动校验. 校验过程可能会花费⼏秒钟).校验完毕后,点击下⽅的创建按钮进行创建.
在创建好的项⽬⻚⾯中点击克隆/下载,以备接下来进⾏下载
⾸次使⽤需要注意这个问题:
克隆远端仓库到本地:
2.5git三大基本命令
git add
将代码放到刚才下载好的⽬录中 git add [⽂件名] 或者git add.最后的 "." 表示当前⽬录
小编这里将我所写的进度条代码放到了linux10文件夹中.
git commit
提交改动到本地
git commit -m "XXX" 提交的时候应该注明提交⽇志,描述改动的详细内容.
git push
同步到远端服务器上
3.调试器---gdb/cgdb使⽤
在Linux C开发中,调试是定位代码问题的核心环节:
gdb:gnu官方的命令行调试器,Linux 下C/C++程序调试的 "标配工具",无图形界面但功能极致强大,能精准控制程序执行、查看内存 / 变量 / 寄存器、定位崩溃原因,解决 "printf 打印调试" 无法覆盖的复杂问题(如内存越界、逻辑死循环、段错误).
cgdb:基于gdb的ncurses库可视化增强版,完全兼容 GDB 所有命令,核心优势是 "分屏显示(代码 + 调试命令)+语法高亮+快捷键操作",比纯命令行 GDB 更友好,新手入门成本更低.
调试的核心价值:从 "靠 printf 打印变量猜问题" 升级为 "精准控制程序执行流程、实时查看内部状态",是 Linux C 开发从 "入门" 到 "熟练" 的必备技能.
3.1样例代码
c
// mycmd.c
#include <stdio.h>
int Sum(int s, int e)
{
int result = 0;
for(int i = s; i <= e; i++)
{
result += i;
}
return result;
}
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;
}
3.2预备工作
程序的发布⽅式有两种,debug 模式和 release 模式,Linux gcc/g++ 出来的⼆进制程序,默认是release模式.
要使⽤gdb调试,必须在源代码⽣成⼆进制程序的时候,加上 -g 选项,如果没有添加,程序⽆法被编译.
bash
$ gcc mycmd.c -o mycmd #默认模式,不⽀持调试
$ file mycmd
mycmd: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically
linked, interpreter /lib64/ld-linux-x86-64.so.2,
BuildID[sha1]=82f5cbaada10a9987d9f325384861a88d278b160, for GNU/Linux
3.2.0, not stripped
$ gcc mycmd.c -o mycmd -g #debug模式
$ file mycmd
mycmd: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically
linked, interpreter /lib64/ld-linux-x86-64.so.2,
BuildID[sha1]=3d5a2317809ef86c7827e9199cfefa622e3c187f, for GNU/Linux
3.2.0, with debug_info, not stripped
3.3常⻅使⽤命令
开始:gdb binFile
退出:ctrl + d 或 quit 调试命令
GDB调试命令汇总表
| 命令 | 作用 | 样例 |
|---|---|---|
list/l |
显示源代码,从上次位置开始,每次列出10行 | list/l 10 |
list/l 函数名 |
列出指定函数的源代码 | list/l main |
list/l 文件名:行号 |
列出指定文件的源代码 | list/l mycmd.c:1 |
r/run |
从程序开始连续执行 | run |
n/next |
单步执行,不进入函数内部,逐过程(对应IDE的F10) | next |
s/step |
单步执行,进入函数内部,逐语句(对应IDE的F11) | step |
break/b [文件名:]行号 |
在指定行号设置断点 | break 10;break test.c:10 |
break/b 函数名 |
在函数开头设置断点 | break main |
info break/b |
查看当前所有断点的信息 | info break |
finish |
执行到当前函数返回,然后停止 | finish |
print/p 表达式 |
打印表达式的值 | print start+end |
p 变量 |
打印指定变量的值 | p x |
set var 变量=值 |
修改变量的值 | set var i=10 |
continue/c |
从当前位置开始连续执行程序 | continue |
delete/d breakpoints |
删除所有断点 | delete breakpoints |
delete/d breakpoints n |
删除序号为n的断点 | delete breakpoints 1 |
disable breakpoints |
禁用所有断点 | disable breakpoints |
enable breakpoints |
启用所有断点 | enable breakpoints |
info/i breakpoints |
查看当前设置的断点列表 | info breakpoints |
display 变量名 |
跟踪显示指定变量的值(每次程序停止时自动展示) | display x |
undisplay 编号 |
取消对指定编号的变量的跟踪显示 | undisplay 1 |
until X行号 |
执行到指定行号 | until 20 |
backtrace/bt |
查看当前执行栈的各级函数调用及参数(定位崩溃核心命令) | backtrace |
info/i locals |
查看当前栈帧的局部变量值 | info locals |
quit |
退出GDB调试器 | quit |
3.4安装gdb/cgdb以及常⻅使用技巧
安装gdb
bash
# Debian/Ubuntu系
sudo apt update && sudo apt install gdb -y
# CentOS/RHEL系
sudo yum install gdb -y
# 验证安装
gdb --version
安装cgdb(需先装依赖)
bash
# Debian/Ubuntu系(先装ncurses依赖)
sudo apt update && sudo apt install cgdb libncurses5-dev libncursesw5-dev -y
# CentOS/RHEL系
sudo yum install cgdb ncurses-devel -y
# 验证安装
cgdb --version
3.4.1watch
执⾏时监视⼀个表达式(如变量)的值.如果监视的表达式在程序运⾏期间的值发⽣变化,gdb会暂停程序的执⾏,并通知使⽤者.
bash
(gdb) l main
int main()
{
int start = 1;
int end = 100;
printf("I will begin\n");
int n = Sum(start, end);
(gdb) b 20
Breakpoint 1 at 0x11c3: file mycmd.c, line 20.
(gdb) info b
Num Type Disp Enb Address What
breakpoint keep y 0x00000000000011c3 in main at mycmd.c:20
(gdb) r
Starting program: /home/whb/test/test/mycmd
I will begin
Breakpoint 1, main () at mycmd.c:20
int n = Sum(start, end);
(gdb) s
Sum (s=32767, e=-7136) at mycmd.c:5
{
(gdb) n
int result = 0;
(gdb) watch result
Hardware watchpoint 2: result
(gdb) c
Continuing.
Hardware watchpoint 2: result
Old value = -6896
New value = 0
Sum (s=1, e=100) at mycmd.c:7
for(int i = s; i <= e; i++)
(gdb) c
Continuing.
Hardware watchpoint 2: result
Old value = 0
New value = 1
Sum (s=1, e=100) at mycmd.c:7
for(int i = s; i <= e; i++)
(gdb) c
Continuing.
Hardware watchpoint 2: result
Old value = 1
New value = 3
Sum (s=1, e=100) at mycmd.c:7
for(int i = s; i <= e; i++)
(gdb) c
Continuing.
Hardware watchpoint 2: result
Old value = 3
New value = 6
Sum (s=1, e=100) at mycmd.c:7
for(int i = s; i <= e; i++)
(gdb) info b
Num Type Disp Enb Address What
breakpoint keep y 0x00005555555551c3 in main at mycmd.c:20
breakpoint already hit 1 time
hw watchpoint keep y result
breakpoint already hit 4 times
(gdb) d 2
(gdb) info b
Num Type Disp Enb Address What
breakpoint keep y 0x00005555555551c3 in main at mycmd.c:20
breakpoint already hit 1 time
(gdb) finish
Run till exit from #0 Sum (s=1, e=100) at mycmd.c:7
0x00005555555551d2 in main () at mycmd.c:20
int n = Sum(start, end);
Value returned is $1 = 5050
📌注意:
如果你有⼀些变量不应该修改,但是你怀疑它修改导致了问题,你可以watch它,如果变化了,就会通知你.监视变量的变化
3.4.2set var确定问题原因
更改⼀下标志位,假设我们想得到 ±result
c
// mycmd.c
#include <stdio.h>
int flag = 0; // 故意错误
//int flag = -1;
//int flag = 1;
int Sum(int s, int e)
{
int result = 0;
for(int i = s; i <= e; i++)
{
result += i;
}
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;
}
bash
(gdb) l main
return result*flag;
int main()
{
int start = 1;
int end = 100;
printf("I will begin\n");
int n = Sum(start, end);
(gdb) b 24
Breakpoint 1 at 0x11ca: file mycmd.c, line 24.
(gdb) r
Starting program: /home/whb/test/test/mycmd
I will begin
Breakpoint 1, main () at mycmd.c:24
int n = Sum(start, end);
(gdb) n
printf("running done, result is: [%d-%d]=%d\n", start, end,
n);
(gdb) n
running done, result is: [1-100]=0 # 这⾥结果为什么是0?
return 0;
(gdb) r
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/whb/test/test/mycmd
I will begin
Breakpoint 1, main () at mycmd.c:24
int n = Sum(start, end);
(gdb) s
Sum (s=32767, e=-7136) at mycmd.c:9
{
(gdb) n
int result = 0;
(gdb) n
for(int i = s; i <= e; i++)
(gdb)
result += i;
(gdb)
for(int i = s; i <= e; i++)
(gdb)
result += i;
(gdb) until 14
Sum (s=1, e=100) at mycmd.c:16
return result*flag;
(gdb) p result
$1 = 5050
(gdb) p flag
$2 = 0
(gdb) set var flag=1 # 更改flag的值,确认是否是它的原因
(gdb) p flag
$3 = 1
(gdb) n
}
(gdb) n
main () at mycmd.c:25
printf("running done, result is: [%d-%d]=%d\n", start, end,
n);
(gdb) n
running done, result is: [1-100]=5050 # 是它的原因
return 0;
3.4.3添加条件断点
bash
(gdb) l main
return result;
int main()
{
int start = 1;
int end = 100;
printf("I will begin\n");
int n = Sum(start, end);
(gdb) b 20
Breakpoint 1 at 0x11c3: file mycmd.c, line 20.
(gdb) r
Starting program: /home/whb/test/test/mycmd
I will begin
Breakpoint 1, main () at mycmd.c:20
int n = Sum(start, end);
(gdb) s
Sum (s=32767, e=-7136) at mycmd.c:5
{
(gdb) n
int result = 0;
(gdb) n
for(int i = s; i <= e; i++)
(gdb) n
result += i;
(gdb) display i
i = 1
(gdb) n
for(int i = s; i <= e; i++)
i = 1
(gdb) n
result += i;
i = 2
(gdb) n
for(int i = s; i <= e; i++)
i = 2
(gdb) n
result += i;
i = 3
(gdb)
for(int i = s; i <= e; i++)
i = 3
(gdb) info b
Num Type Disp Enb Address What
breakpoint keep y 0x00005555555551c3 in main at mycmd.c:20
breakpoint already hit 1 time
(gdb) b 9 if i == 30 # 9是⾏号,表⽰新增断点的位置
Breakpoint 2 at 0x555555555186: file mycmd.c, line 9.
(gdb) info b
Num Type Disp Enb Address What
breakpoint keep y 0x00005555555551c3 in main at mycmd.c:20
breakpoint already hit 1 time
breakpoint keep y 0x0000555555555186 in Sum at mycmd.c:9
stop only if i == 30
(gdb) finish
Run till exit from #0 Sum (s=1, e=100) at mycmd.c:7
Breakpoint 2, Sum (s=1, e=100) at mycmd.c:9
result += i;
i = 30
(gdb) finish
Run till exit from #0 Sum (s=1, e=100) at mycmd.c:9
0x00005555555551d2 in main () at mycmd.c:20
int n = Sum(start, end);
Value returned is $1 = 5050
3.4.4给已经存在的断点新增条件
bash
(gdb) l main
return result;
int main()
{
int start = 1;
int end = 100;
printf("I will begin\n");
int n = Sum(start, end);
(gdb) b 20
Breakpoint 1 at 0x11c3: file mycmd.c, line 20.
(gdb) r
Starting program: /home/whb/test/test/mycmd
I will begin
Breakpoint 1, main () at mycmd.c:20
int n = Sum(start, end);
(gdb) s
Sum (s=32767, e=-7136) at mycmd.c:5
{
(gdb) n
int result = 0;
(gdb) n
for(int i = s; i <= e; i++)
(gdb) n
result += i;
(gdb)
for(int i = s; i <= e; i++)
(gdb)
result += i;
(gdb)
for(int i = s; i <= e; i++)
(gdb)
result += i;
(gdb)
for(int i = s; i <= e; i++)
(gdb) b 9 # 我们在第9⾏新增⼀个断点,⽤来开始测试
Breakpoint 2 at 0x555555555186: file mycmd.c, line 9.
(gdb) info b
Num Type Disp Enb Address What
breakpoint keep y 0x00005555555551c3 in main at mycmd.c:20
breakpoint already hit 1 time
breakpoint keep y 0x0000555555555186 in Sum at mycmd.c:9
(gdb) n
Breakpoint 2, Sum (s=1, e=100) at mycmd.c:9
result += i;
(gdb) n
for(int i = s; i <= e; i++)
(gdb) n
Breakpoint 2, Sum (s=1, e=100) at mycmd.c:9
result += i;
(gdb) condition 2 i==30 #给2号断点,新增条件i==30
(gdb) info b
Num Type Disp Enb Address What
breakpoint keep y 0x00005555555551c3 in main at mycmd.c:20
breakpoint already hit 1 time
breakpoint keep y 0x0000555555555186 in Sum at mycmd.c:9
stop only if i==30
breakpoint already hit 2 times
(gdb) n
for(int i = s; i <= e; i++)
(gdb) n
result += i;
(gdb) c
Continuing.
Breakpoint 2, Sum (s=1, e=100) at mycmd.c:9
result += i;
(gdb) p i
$1 = 30
(gdb) p result
$2 = 435
📌注意:
条件断点添加常⻅两种⽅式:1. 新增 2. 给已有断点追加 注意两者的语法有区别,不要写错了. 新增:b ⾏号/⽂件名:⾏号/函数名 if i == 30 (条件) 给已有断点追加:condition 2 i==30,其中 2 是已有断点编号,没有ifcgbd分屏操作 ESC 进⼊代码屏,i 回到gdb屏.
4.附录(给不同系统安装源)
4.1Centos7更新yum源
在CentOS 7中更新Yum源可以通过以下步骤完成:
1️⃣备份现有Yum源
在更新之前,建议备份现有的Yum源配置⽂件:
bash
sudo mkdir /etc/yum.repos.d/backup
sudo mv /etc/yum.repos.d/*.repo /etc/yum.repos.d/backup/
2️⃣下载新的Yum源配置⽂件
CentOS 7默认使⽤CentOS官⽅源,如果需要使⽤其他源(如阿⾥云、清华源等),可以⼿动下载对应的配置⽂件.
使⽤阿⾥云源使⽤清华源
bash
sudo curl -o /etc/yum.repos.d/CentOS-Base.repo
http://mirrors.aliyun.com/repo/Centos-7.repo
sudo curl -o /etc/yum.repos.d/CentOS-Base.repo
https://mirrors.tuna.tsinghua.edu.cn/repo/Centos-7.repo
3️⃣清理并⽣成缓存
更新Yum源后,清理旧的缓存并⽣成新的缓存:
bash
sudo yum clean all
sudo yum makecache
4️⃣更新系统
更新Yum源后,可以更新系统以确保所有软件包都是最新的:
bash
sudo yum update
5️⃣恢复原有Yum源(可选)
如果需要恢复原有的Yum源,可以将备份的配置⽂件移回原⽬录:
bash
sudo mv /etc/yum.repos.d/backup/*.repo /etc/yum.repos.d/
6️⃣验证Yum源
可以通过以下命令验证Yum源是否更新成功:
bash
sudo yum repolist
4.2Ubuntu更新apt源
如果你想直接下载并替换Ubuntu 20.04(Focal Fossa)的APT源配置⽂件,以下是具体步骤:
1️⃣备份现有APT源
在替换之前,先备份现有的APT源配置⽂件:
bash
sudo cp /etc/apt/sources.list /etc/apt/sources.list.bak
2️⃣直接下载新的APT源配置⽂件
根据你选择的镜像源,直接下载并替换配置⽂件.
阿⾥云源运⾏以下命令下载阿⾥云源配置⽂件:
清华源运⾏以下命令下载清华源配置⽂件:
bash
sudo wget -O /etc/apt/sources.list http://mirrors.aliyun.com/repo/ubuntusources.list
sudo wget -O /etc/apt/sources.listhttps://mirrors.tuna.tsinghua.edu.cn/ubuntu/sources.list
3️⃣确保配置⽂件适配Ubuntu 20.04
下载的源⽂件可能包含多个Ubuntu版本的配置.你需要确保⽂件中的配置是针对Ubuntu 20.04(Focal Fossa))的.打开⽂件检查:确保每⾏中包含 focal
如果⽂件中包含其他版本的配置(如 bionic 或 jammy),可以⼿动删除或注释掉.
bash
sudo nano /etc/apt/sources.list
deb http://mirrors.aliyun.com/ubuntu/ focal main restricted universe
multiverse
deb http://mirrors.aliyun.com/ubuntu/ focal-security main restricted universe
multiverse
deb http://mirrors.aliyun.com/ubuntu/ focal-updates main restricted universe
multiverse
deb http://mirrors.aliyun.com/ubuntu/ focal-proposed main restricted universe
multiverse
deb http://mirrors.aliyun.com/ubuntu/ focal-backports main restricted
universe multiverse
4️⃣更新APT缓存
替换源⽂件后,更新APT缓存:
bash
sudo apt update
5️⃣升级系统(可选)
如果需要升级系统中的所有软件包,可以运⾏;或者全⾯升级(包括内核和依赖):
bash
sudo apt upgrade
sudo apt full-upgrade
6️⃣验证APT源
可以通过以下命令查看当前的APT源是否⽣效:
bash
sudo apt policy
7️⃣恢复原有APT源(可选)
如果需要恢复原有的APT源,可以将备份的⽂件还原:
bash
sudo cp /etc/apt/sources.list.bak /etc/apt/sources.list
sudo apt update
敬请期待下一篇文章内容-->深入剖析git的原理和使用!









