Linux基础开发工具(gcc/g++,yum,vim,make/makefile)

目录

软件包管理器——yum

Linux下,软件的安装

yum与软件包的关系

yum命令的运用

1.查看软件包

2.安装/删除软件包

编辑器——vim

vim的基本概念

vim的基本操作

命令模式命令

移动光标

删除文字

撤销上一次操作

跳至指定的行

底行模式命令

编译器——gcc/g++

预处理

编译

汇编

链接

动态链接与静态链接

总结

自动化构建——make/makefile

基本概念

实例

细节

语法扩展

Linux第⼀个系统程序——进度条

预备知识

练手——倒计时小程序

进度条简约版

进度条进阶版

调试器 - gdb/cgdb

预备知识点

常见命令

watch

条件断点

新建条件断点

在新增断点上设置条件


软件包管理器——yum

CentOS版本用yum,Ubuntu版本用apt。

Linux下,软件的安装

安装方法有三:

1.源码安装。下载程序的源代码,并进行编译,得到可执行程序。

2.rpm安装方式。使用 rpm 命令来安装 .rpm 格式的软件包。(不会自动解决依赖关系)

3.yum工具级别安装。(自动解决依赖关系)

注:这里的依赖关系是指一个软件可能需要依赖多个库才能实现。

yum与软件包的关系

yum命令的运用

1.查看软件包

[slm@localhost d1]$ yum list | grep lrzsz
lrzsz.x86_64                             0.12.20-36.el7                @anaconda

注:

1,x86_64后缀表示64位系统的安装包、

2.el7表示的是操作系统发行版的版本。el7表示的是centos7

3.base表示的是“软件源的名称。

2.安装/删除软件包

sudo yum install -y 要安装的软件
sudo yum remove -y 要卸载的软件

;安装要以超级用户的身份进行,拷贝下来的软件会在指定的系统目录中。

编辑器——vim

vim的基本概念

vim有很多中模式但我们掌握三种即可。三种模式分别是:命令模式,插入模式,底行模式。

用一张图来清晰解决三种模式的切换命令:

三种模式的特点:

命令模式:用命令对文件内容进行删除或者控制光标的移动等。

插入模式:可以用键盘的输入对文件内容进行修改。

底行模式:文件保存或退出,也可以进行文件替换,找字符串,列出行号等操作。

vim的基本操作

先进入文件 tmp.c

[slm@localhost d1]$vim tmp.c

命令模式命令

移动光标

按「G」:移动到文章的最后
按「 $ 」:移动到光标所在行的“行尾”
按「^」:移动到光标所在行的“行首”
按「w」:光标跳到下个字的开头
按「e」:光标跳到下个字的字尾
按「b」:光标回到上个字的开头
按「#l」:光标移到该行的第#个位置,如:5l,56l
按[gg]:进入到文本开始
按[shift+g]:进入文本末端
按「ctrl」+「b」:屏幕往“后”移动⼀页
按「ctrl」+「f」:屏幕往“前”移动⼀页
按「ctrl」+「u」:屏幕往“后”移动半页
按「ctrl」+「d」:屏幕往“前”移动半页

删除文字

「yw」:将光标所在之处到字尾的字符复制到缓冲区中。
「#yw」:复制#个字到缓冲区
「yy」:复制光标所在行到缓冲区。
「#yy」:例如,「6yy」表示拷贝从光标所在的该行“往下数”6行⽂字。
「p」:将缓冲区内的字符贴到光标所在位置。注意:所有与“y”有关的复制命令都必须
与“p”配合才能完成复制与粘贴功能。

撤销上一次操作


「u」:如果您误执行⼀个命令,可以马上按下「u」,回到上⼀个操作。按多次“u”可以执行
多次回复。
「ctrl + r」: 撤销的恢复

跳至指定的行


「ctrl」+「g」列出光标所在行的行号。
「#G」:例如,「15G」,表示移动光标至文章的第15行行首。

底行模式命令

列出行号
• 「set nu」: 输⼊「set nu」后,会在⽂件中的每⼀行前⾯列出行号。
• 跳到⽂件中的某⼀行
• 「#」:「#」号表示⼀个数字,在冒号后输⼊⼀个数字,再按回⻋键就会跳到该行了,如输⼊数字
15,再回⻋,就会跳到⽂章的第15行。
查找字符
• 「/关键字」: 先按「/」键,再输⼊您想寻找的字符,如果第⼀次找的关键字不是您想要的,可以
⼀直按「n」会往后寻找到您要的关键字为⽌。
• 「?关键字」:先按「?」键,再输⼊您想寻找的字符,如果第⼀次找的关键字不是您想要的,可
以⼀直按「n」会往前寻找到您要的关键字为⽌。
保存⽂件
• 「w」: 在冒号输⼊字⺟「w」就可以将⽂件保存起来
离开vim
• 「q」:按「q」就是退出,如果⽆法离开vim,可以在「q」后跟⼀个「!」强制离开vim。
• 「wq」:⼀般建议离开时,搭配「w」⼀起使⽤,这样在退出的时候还可以保存文件。

•  「q!」:不存盘强制退出vim

其他指令:

!man+函数:查询函数

!command:不离开vim,进入到命令行输入页

vs+文件名:一个窗口产生多个文件,如果文件不存在就新建

ctrl+ww:两个窗口之间关标切换

在命令行模式下批量化注释:

1.ctrl+v:进入可视化模式

2.按hjkl键选择要注释的行

3.shift+i=I//进入插入模式

4.按//

5.按两下Esc键

去注释:

1.ctrl+v:进入可视化模式

2.按hjkl键选择要删除的部分

3.按d键删除

编译器——gcc/g++

预处理

作用:进行宏替换/去注释/条件编译/头文件展开等

gcc -E hello.c -o hello.i

//选项”-E“作用是让gcc在预处理结束后停止编译过程

//选项”-o“是指目标文件,".i"文件是预处理的C原始程序

1、头文件展开就是直接把头文件中相关的内容拷贝到源文件中,所以预处理后就不需要头文件

2、条件编译(#if——#else——#endif),本质是对代码进行裁剪。比如我们下载软件的时候有时候会遇到社区版/专业版,在社区版中我们没有专业版软件的一些功能,两个版本的代码是差不多的,只是两个版本都新增了一些不同的代码让这两个版本之间产生差别。

3.gcc可以对代码进行增、删、改

编译

作用:检查代码的规范性。是否有语法错误等,检查无误后生成汇编语言。

gcc -S code.i -o code.s

//选项”S“的作用是让gcc在编译结束后停止汇编的过程

汇编

作用:生成机器可识别代码

gcc -c code.s -o code.o

//选项”c“的作用是让gcc在汇编结束后停止链接的过程

//不能直接执行,因为.o文件还没有定位到库文件中函数的地址,即还没有把正确的地址补在”地址还不确定的“机器码上。

链接

作用:生成可执行文件或库文件

gcc hello.o –o hello

//从.c文件直接形成可执行文件

gcc hello.c -o hello //形成hello可执行文件

gcc -o hello hello.c //形成hello可执行文件

gcc hello.c //形成a.out可执行文件

//牢记小秘诀:-o后面都是执行文件

在上面的链接的过程中我们发现想要链接成功系统里就必须安装好库和头文件,不然找不到函数的地址,所以为什么要有库呢?

库的分类

常见的库有两种:动态库和静态库

动态库:在Linux下,后缀为”.so“;在windows下,后缀为”.dll“

静态库:在Linux下,后缀为”.a“;在windows下,后缀为”.lib”

库的命名

在Linux下,静态库:"libXXX.a",其中XXX是静态库的名字;动态库:“libXXX.so”,其中XXX是动态库的名字。

 两种库的区别

静态库:会在磁盘进行链接时把库文件的代码全部加入到可执行文件中(实际上就是拷贝),所以生成的文件比较大,但是运行时不需要库文件了

动态库:在编译链接时并没有把库文件的代码加入到可执行文件中,而是在运行可执行文件时链接需要的库文件加载到可执行文件中,这样可以节省系统的开销。

两种库的优缺点

动态库静态库
优点节省资源不依赖任何库,可以独立运行
缺点一旦丢失,所有程序无法直接运行体积大,占据资源多,加载速度受影响

静态库和动态库的生成

gcc test.c -o test//形成动态链接

gcc test.c -o test_static   -static//形成静态链接,比动态链接占用的空间大

ldd命令是查询文件依赖的库文件。

注:gcc默认生成的二进制程序,是动态链接的,可以用file命令检验。

动态链接与静态链接

动态链接就是把程序按照模块拆分成各个相对独立部分,在程序运⾏时才将它们链接在⼀起形成⼀个完整的程序。每个程序里面的库函数都是共用一个库的。

静态链接就是把代码需要的函数直接拷贝到可执行文件中,每个程序里面的库函数都要拷贝一份库函数代码,会产生很多副本。

总结

1.预处理(去注释/展开头文件/进行宏替换/条件编译等)

2.编译(检查代码规范性,检查语法错误,无误后生成汇编语言)

3.汇编(生成机器可识别二进制代码)

4.链接(生成可执行文件)

5.形成不同阶段文件的简易记法:Esc键变成ESc

有时候我们老是代码写完了,但是运行的时候会报错,但是修改完代码后,又要开始重新形成目标文件,万一我们的错误改了又错呢,错很多遍的话这样就会很麻烦。如果有个文件一直保存这条命令的话那我每次运行的时候就不需要自己又输一遍了。

自动化构建——make/makefile

基本概念

作用:一旦写好makefile,只需要一个make命令就可以让整个工程完全自动编译,极大提高了软件开发的效率。

make是解释makefile文件中指令的命令,所以make是一条命令,makefile是一个文件。

实例

test_9_10:test_9_10.cgcc -o test_9_10 test_9_10.c
.PHONY:clean
clean:rm -f test_9_10

规范:

细节

[root@localhost d1]# ll
总用量 904
drwxr-xr-x. 3 root root     16 3月  13 15:32 d2
-rw-r--r--. 1 root root     89 9月  10 15:30 makefile
-rwxr-xr-x. 1 root root   8664 9月  10 11:13 test
-rw-r--r--. 1 root root    204 9月  10 15:27 test_9_10.c
-rw-r--r--. 1 root root    553 9月  10 14:19 test.c
-rwxr-xr-x. 1 root root 900440 9月  10 11:13 test_static
[root@localhost d1]# make
gcc -o test_9_10 test_9_10.c
[root@localhost d1]# ll
总用量 916
drwxr-xr-x. 3 root root     16 3月  13 15:32 d2
-rw-r--r--. 1 root root     89 9月  10 15:30 makefile
-rwxr-xr-x. 1 root root   8664 9月  10 11:13 test
-rwxr-xr-x. 1 root root   8416 9月  10 15:31 test_9_10
-rw-r--r--. 1 root root    204 9月  10 15:27 test_9_10.c
-rw-r--r--. 1 root root    553 9月  10 14:19 test.c
-rwxr-xr-x. 1 root root 900440 9月  10 11:13 test_static
[root@localhost d1]# make
make: “test_9_10”是最新的。
[root@localhost d1]# make clean
rm -f test_9_10
[root@localhost d1]# make clean
rm -f test_9_10
[root@localhost d1]# make clean
rm -f test_9_10

在上面的代码中我们发现

问题1:make命令后只有一条执行指令,clean怎么不执行?

问题2:make命令执行后后面在执行就会显示文件是最新的,不会执行,但是clean却能一直执行

问题一:make、makefile默认只形成一个目标,就是从上到下遇到的第一个目标。但是如果第一条指令中依赖文件列表在该目录下没有,那么make就会往下面找,就会执行多条指令。

//makefile文件
test_9_10:test_9_10.ogcc -o test_9_10 test_9_10.o
test_9_10.o:test_9_10.sgcc -c test_9_10.s -o test_9_10.o
test_9_10.s:test_9_10.igcc -S test_9_10.i -o test_9_10.s
test_9_10.i:test_9_10.cgcc -E test_9_10.c -o test_9_10.i
.PHONY:clean
clean:rm -f test_9_10 *.i *.s *.o
[root@localhost d1]# ll
总用量 904
drwxr-xr-x. 3 root root     16 3月  13 15:32 d2
-rw-r--r--. 1 root root    278 9月  10 16:03 makefile
-rwxr-xr-x. 1 root root   8664 9月  10 11:13 test
-rw-r--r--. 1 root root    204 9月  10 15:27 test_9_10.c
-rw-r--r--. 1 root root    553 9月  10 14:19 test.c
-rwxr-xr-x. 1 root root 900440 9月  10 11:13 test_static
[root@localhost d1]# make
gcc -E test_9_10.c -o test_9_10.i
gcc -S test_9_10.i -o test_9_10.s
gcc -c test_9_10.s -o test_9_10.o
gcc -o test_9_10 test_9_10.o
[root@localhost d1]# ll
总用量 944
drwxr-xr-x. 3 root root     16 3月  13 15:32 d2
-rw-r--r--. 1 root root    278 9月  10 16:03 makefile
-rwxr-xr-x. 1 root root   8664 9月  10 11:13 test
-rwxr-xr-x. 1 root root   8416 9月  10 16:03 test_9_10
-rw-r--r--. 1 root root    204 9月  10 15:27 test_9_10.c
-rw-r--r--. 1 root root  16921 9月  10 16:03 test_9_10.i
-rw-r--r--. 1 root root   1616 9月  10 16:03 test_9_10.o
-rw-r--r--. 1 root root    576 9月  10 16:03 test_9_10.s
-rw-r--r--. 1 root root    553 9月  10 14:19 test.c
-rwxr-xr-x. 1 root root 900440 9月  10 11:13 test_static

问题2:首先我们先了解“.PHONY”表示被修饰的目标是一个伪目标,伪目标总是要执行的。总是要执行就表示它不需要对比源文件和exe的修改时间,只要make它的指令就会可以一直执行。

 [root@localhost d1]#stat test_9_10.c文件:"test_9_10.c"大小:204       	块:8          IO 块:4096   普通文件
设备:fd00h/64768d	Inode:33600218    硬链接:1
权限:(0644/-rw-r--r--)  Uid:(    0/    root)   Gid:(    0/    root)
环境:unconfined_u:object_r:home_root_t:s0
最近访问:2025-09-10 15:31:25.887293504 +0800
最近更改:2025-09-10 15:27:21.934213096 +0800
最近改动:2025-09-10 15:27:21.936213031 +0800
创建时间:-
[root@localhost d1]# vim test_9_10.c
[root@localhost d1]# stat test_9_10.c文件:"test_9_10.c"大小:216       	块:8          IO 块:4096   普通文件
设备:fd00h/64768d	Inode:33600234    硬链接:1
权限:(0644/-rw-r--r--)  Uid:(    0/    root)   Gid:(    0/    root)
环境:unconfined_u:object_r:home_root_t:s0
最近访问:2025-09-10 19:39:14.639976185 +0800
最近更改:2025-09-10 19:39:14.639976185 +0800
最近改动:2025-09-10 19:39:14.642975744 +0800
创建时间:-
//⽂件 = 内容 + 属性
//Modify: 内容变更,时间更新(最近改动)
//Change:属性变更,时间更新(最近更改)
//Access:常指的是⽂件最近⼀次被访问的时间。在Linux的早期版本中,每当⽂件被访问时,其
//atime都会更新。但这种机制会导致⼤量的IO操作。具体更新原则,不做过多解释。

make执行第一条不是伪目标的指令时,会先比较文件的源文件是否在可执行文件的前后时间,来决定是否要重新编译。如果源文件的修改时间比可执行文件晚,那么就不需要重新编译,否则,需要。

语法扩展

BIN=proc.exe定义变量(类似于宏替换)
SRC=$(shell ls *.c) 采⽤shell命令⾏⽅式,获取当前所有.c⽂件名
SRC=$(wildcard *.c)使⽤ wildcard 函数,获取当前所有.c⽂件名
OBJ=$(SRC:.c=.o)将SRC的所有同名.c 替换 成为.o 形成⽬标⽂件列表
LFLAGS=-o链接选项
FLAGS=-c编译选项
RM=rm -f引⼊命令
$(BIN):$(OBJ)
@$(CC) $(LFLAGS) $@ $^
$@:代表⽬标⽂件名。 $^: 代表依赖⽂件列表
@$(CC) $(FLAGS) $<%<: 对展开的依赖.c⽂件,⼀个⼀个的交给gcc。
@echo "compling ... $< to $@" @:不回显命令,如果不加 @,终端会显示:

echo "compling ... xxx.c to xxx.o"

然后再显示:

compling ... xxx.c to xxx.o

加了 @,终端只会显示:

compling ... xxx.c to xxx.o

clean:
$(RM) $(OBJ) $(BIN)
#
$(RM): 替换,⽤变量内容替换它
%.o:%.c%.c 展开当前⽬录下所有的.c。 %.o: 同时展开同
名.o

实例:

  1 BIN=test_9_102 SRC=$(wildcard *.c)3 OBJ=$(SRC:.c=.o)4 LFLAGS=-o5 FLAGS=-c6 CC=gcc7 RM= rm -f8 $(BIN):$(OBJ)9     @$(CC) $(LFLAGS) $@ $^10 %.o:%.c11     @$(CC) $(FLAGS) $<     12     @echo "compling ...$< to $@"13 .PHONY:clean14 clean:15       $(RM) $(OBJ) $(BIN)  //相当于rm -f *.o test_9_10

执行make指令:

[root@localhost d1]# make
compling ...test_9_10.c to test_9_10.o
[root@localhost d1]# ll
总用量 904
drwxr-xr-x. 3 root root     16 3月  13 15:32 d2
-rw-r--r--. 1 root root    228 9月  10 20:42 makefile
-rwxr-xr-x. 1 root root   8416 9月  10 20:35 test_9_10
-rw-r--r--. 1 root root    204 9月  10 20:35 test_9_10.c
-rw-r--r--. 1 root root   1616 9月  10 20:35 test_9_10.o
-rwxr-xr-x. 1 root root 900440 9月  10 11:13 test_static
[root@localhost d1]# make clean
rm -f test_9_10.o test_9_10
[root@localhost d1]# ll
总用量 888
drwxr-xr-x. 3 root root     16 3月  13 15:32 d2
-rw-r--r--. 1 root root    228 9月  10 20:42 makefile
-rw-r--r--. 1 root root    204 9月  10 20:35 test_9_10.c
-rwxr-xr-x. 1 root root 900440 9月  10 11:13 test_static

Linux第⼀个系统程序——进度条

预备知识

回车(\r)/换行(\n):

\r:把光标移到行首(不换行)

\n:把光标移到下一行

行缓冲区:

函数:fflush

#include<stdio.h>   int fflush(FILE*stream)//把用户缓冲区的内容刷新到内核缓冲区中,并写在文件stream中

比较下面三种结果有何不同:

  1 #include<stdio.h>2 int main()3 {4     printf("hello world\n");5     sleep(3);6     return 0;7 }

现象:立马打印“hello world”,然后光标在下一行闪烁三秒,然后打印命令条

  1 #include<stdio.h>2 int main()3 {4     printf("hello world");5     sleep(3);6     return 0;7 }

现象:等待三秒后才打印“hello world”,然后在同一行上打印命令条

  1 #include<stdio.h>2 int main()3 {4     printf("hello world");5     fflush(stdout);6     sleep(3);7     return 0;8 }

现象:立马打印“hello world”,等待三秒后,然后在同一行上打印命令条

所以从上面的现象可以得出,

1.回车键和fflush函数可以进行行缓冲,把用户缓冲区的内容刷新到内核缓冲区并刷新到输出设备上。

2.程序结束也会自动刷新缓冲区。

练手——倒计时小程序

  1 #include<stdio.h>2 int main()3 {4     int i=20;5     while(i--)6     {7         printf("%-2d\r",i);//保留两位数字8         fflush(stdout);9         sleep(1);10 11     }12     printf("\n");13     return 0;14 }

进度条简约版

  //每秒加载1%1 #include<stdio.h>2 #include<string.h>3 int main()4 {5     char str[101]={0};6     int i=0;7     for(i=0;i<=100;i++)8     {9         printf("[%-100s]    %d%%\r",str,i);10         str[i]='#';11         fflush(stdout);12         sleep(1);13 14     }15     printf("\n");16 17     return 0;18 }

我们常见的进度条都是会根据我们的网速来确定加载了多少,所以我们来实现一个进阶版

进度条进阶版

[root@localhost d1]# ./process
[####################################################################################################]  [-]  [100%]
download 1025.00MB Done
 

main.c

  1 #include"process.h"2 double speed=1.0;3 double size=1024.0;4 void download()5 {6 7     double current=0;8     while(current<=size)9     {10         //打印进度条11         PrintfProcess(current,size);12         current+=speed;//注释掉,可以观察到进度一直在加载13         usleep(20000);14     }15     printf("\ndownload %.2lfMB Done\n",current);//current类型写错,输出0.0016 }17 int main()18 {19     download();20     return 0;21 }

process.c

  1 #include"process.h"2 void PrintfProcess(double current,double size)3 {4     char str[101];5     memset(str,0,sizeof(str));6     const char*lable="-\\|/";//“\\”转义字符用来表示进度的加载效率7     int len=strlen(lable);8     int i=0;9     int num=(int)(current/size*100);10     for(i=0;i<num;i++)11     {12         str[i]='#';13     }14     static int cnt;15     cnt%=len;16     printf("[%-100s]  [%c]  [%.lf%%]\r",str,lable[cnt],current/size*100);17     cnt++;//即使卡顿了也一直在加载,检测网络在不在线18     fflush(stdout);19 }

lable字符串的作用:

process.h

  1 #pragma once2 #include<stdio.h>3 #include<unistd.h>4 #include<string.h>5 void PrintfProcess(double current,double size);

makefile

  1 SRC=$(wildcard *.c)2 OBJ=$(SRC:.c=.o)3 BIN=process4 $(BIN):$(OBJ)5     gcc -o $@ $^6 %.o:%.c7     gcc -c $<8 .PHONY:clean9 clean:10     rm -f $(OBJ) $(BIN)

调试器 - gdb/cgdb

样例代码:

// 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;
}

预备知识点

1.程序有两种发布方式,debug模式和release模式。Linux gcc/g++出来的二进制程序,默认时release模式。

2.debug模式才允许被调试,所以要使用gdb调试,必须在源代码生成二进制程序的时候,加上-g选项,如果没有添加,就不能进行调试。

[root@localhost d1]# gcc -o mycmd mycmd.c//默认模式,不支持调试
[root@localhost d1]# gdb mycmd
(gdb) l 1
No symbol table is loaded.  Use the "file" command.
(gdb) quit
[root@localhost d1]# gcc -o mycmd mycmd.c -g//debug模式,支持调试
[root@localhost d1]# gdb mycmd
(gdb) l 1
5       int i;

常见命令

进入调试:gdb+可执行文件

退出调试:ctrl+d或q

命令作⽤样例
list/l显示源代码,从源文件中光标那行开始list/l 10
list/l 函数名列出指定函数的源代码list/l mian
list/l 文件名:行号列出指定文件的源代码,如果只要指定的哪一行,那么就先设置 set listsize 1,就可以指定看哪一行,否则都是从第一行开始展示list/l mycmd.c:1
r/run从程序开始连续执行run
n/next单步执行,不进入函数内部,相当于逐过程F10next
s/step单步执行,进入函数内部,相当于逐语句F11
break/b 在指定行号设置断点

b 10

break mycmd.c 10

break/b 函数名在函数开头设置断点break main
info break/b查看所有断点信息info break
finish执行到当前函数的返回,然后停止
print/p 表达式打印表达式的值print end+start
 p 变量打印指定变量的值p x
set var 变量=值修改变量的值set var i=10
continue/c从当前位置开始连续执行程序continue
delete/d breakpoints删除所有断点
delete/d breakpoints n删除序号为n的断点delete/d breakpoints 1
disable breakpoints禁用所有断点
enable breakpoints启用所有断点
display 变量名跟踪显示指定变量的值(每次停止时)display x
undisplay 编号取消对指定编号的变量的跟踪显示undisplay 1
until x行号执行到指定行号until 10
backtrace/bt查看当前执行栈的各级函数调用及参数
info/i locals查看当前栈帧的局部变量值
quit/q退出gdb调试器

注:n、s、finish、c、display/undisplay、until都必须在执行期间才可以使用。

watch

执行时监视⼀个表达式(如变量)的值。如果监视的表达式在程序运行期间的值发生变化,GDB 会暂停程序的执行,并通知使用者。

(gdb) l main
8				 result += i;
9		  }
10		 return result;
11	}
12	int main()
13	{
14		 int start = 1;
15		 int end = 100;
16		 printf("I will begin\n");
17		int n = Sum(start, end);
(gdb) b 17
Breakpoint 1 at 0x4005cd: file mycmd.c, line 17.
(gdb) r
Starting program: /home/d1/mycmd 
I will beginBreakpoint 1, main () at mycmd.c:17
17		int n = Sum(start, end);
Missing separate debuginfos, use: debuginfo-install glibc-2.17-326.el7_9.3.x86_64
(gdb) s
Sum (s=1, e=100) at mycmd.c:4
4		 int result = 0;
(gdb) n
6		 for(i = s; i <= e; i++)
(gdb) watch result
Hardware watchpoint 2: result
(gdb) c
Continuing.
Hardware watchpoint 2: resultOld value = 0
New value = 1
Sum (s=1, e=100) at mycmd.c:6
6		 for(i = s; i <= e; i++)
(gdb) c
Continuing.
Hardware watchpoint 2: resultOld value = 1
New value = 3
Sum (s=1, e=100) at mycmd.c:6
6		 for(i = s; i <= e; i++)

注:如果你有一些变量不应该修改,但是你怀疑它修改导致了问题,你可以watch它,如
果变化了,就会通知。

条件断点

实际上就是在设置断点的时候给断点加个条件,当运行起来后finish就会停在设置条件的那个位置。比如 b 8 if i==30,那么程序就会在第八行且i=30的时候停止执行。可以验证中间部分是否结果错误。

新建条件断点

(gdb) l Sum
1	#include <stdio.h>
2	int Sum(int s, int e)
3	{
4		 int result = 0;
5		 int i;
6		 for(i = s; i <= e; i++)
7		 {
8				 result += i;
9		  }
10		 return result;
(gdb) l main
8				 result += i;
9		  }
10		 return result;
11	}
12	int main()
13	{
14		 int start = 1;
15		 int end = 100;
16		 printf("I will begin\n");
17		int n = Sum(start, end);
(gdb) b 17
Breakpoint 1 at 0x4005cd: file mycmd.c, line 17.
(gdb) r
Starting program: /home/d1/mycmd 
I will beginBreakpoint 1, main () at mycmd.c:17
17		int n = Sum(start, end);
Missing separate debuginfos, use: debuginfo-install glibc-2.17-326.el7_9.3.x86_64
(gdb) s
Sum (s=1, e=100) at mycmd.c:4
4		 int result = 0;
(gdb) s
6		 for(i = s; i <= e; i++)
(gdb) n
8				 result += i;
(gdb) n
6		 for(i = s; i <= e; i++)
(gdb) n
8				 result += i;
(gdb) b 8 if i==30
Breakpoint 2 at 0x400596: file mycmd.c, line 8.
(gdb) display i
1: i = 2
(gdb) finish
Run till exit from #0  Sum (s=1, e=100) at mycmd.c:8Breakpoint 2, Sum (s=1, e=100) at mycmd.c:8
8				 result += i;
1: i = 30
(gdb) p result//可以查看result的值
$1 = 435

在新增断点上设置条件

(gdb) b 17
Breakpoint 1 at 0x4005cd: file mycmd.c, line 17.
(gdb) r
Starting program: /home/d1/mycmd 
I will begin

Breakpoint 1, main () at mycmd.c:17
17        int n = Sum(start, end);
Missing separate debuginfos, use: debuginfo-install glibc-2.17-326.el7_9.3.x86_64
(gdb) s
Sum (s=1, e=100) at mycmd.c:4
4         int result = 0;
(gdb) s
6         for(i = s; i <= e; i++)
(gdb) n
8                 result += i;
(gdb) n
6         for(i = s; i <= e; i++)
(gdb) n
8                 result += i;
(gdb) n
6         for(i = s; i <= e; i++)
(gdb) n
8                 result += i;
(gdb) b
Breakpoint 2 at 0x400596: file mycmd.c, line 8.
(gdb) info b
Num     Type           Disp Enb Address            What
1       breakpoint     keep y   0x00000000004005cd in main at mycmd.c:17
    breakpoint already hit 1 time
2       breakpoint     keep y   0x0000000000400596 in Sum at mycmd.c:8
(gdb) condition 2 i==30 //不需要if
(gdb) info b
Num     Type           Disp Enb Address            What
1       breakpoint     keep y   0x00000000004005cd in main at mycmd.c:17
    breakpoint already hit 1 time
2       breakpoint     keep y   0x0000000000400596 in Sum at mycmd.c:8
    stop only if i==30
    breakpoint already hit 2 times
(gdb) n
6         for(i = s; i <= e; i++)
(gdb) n
8                 result += i;
(gdb) c
Continuing.

Breakpoint 2, Sum (s=1, e=100) at mycmd.c:8
8                 result += i;
(gdb) p i
$2 = 30
(gdb) p result
$3 = 435

注:Ctrl+X松开后按a就可以进入GDB TUI(Text User Interface)模式 下的分屏操作,按Esc可以切换到源代码区域,可以按上下键实现翻页;按i键可以切换回gdb模式。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/bicheng/98080.shtml
繁体地址,请注明出处:http://hk.pswp.cn/bicheng/98080.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

数据结构之跳表

跳表&#xff08;Skip List&#xff09;是一种基于概率平衡的数据结构&#xff0c;通过多层有序链表实现高效的查找、插入和删除操作。它在最坏情况下时间复杂度为 (O(n))&#xff0c;但通过随机化设计&#xff0c;平均时间复杂度可优化至 (O(\log n))&#xff0c;与平衡二叉搜…

线程概念,控制

一、线程概念 线程概念&#xff1a;进程内部的一个执行流&#xff0c;轻量化。 观点&#xff1a;进程是系统分配资源的基本单位&#xff0c;线程是CPU调度的基本单位。 在理解线程之前&#xff0c;我们在谈一下虚拟地址空间。 我们都知道进程是通过页表将虚拟地址转化为物理地址…

RabbitMQ 高可用实战篇(Mirrored Queue + Cluster + 持久化整合)

RabbitMQ 高可用实战篇&#xff08;Mirrored Queue Cluster 持久化整合&#xff09;1. 前言 在生产环境中&#xff0c;单节点 RabbitMQ 容易因故障导致消息丢失或业务中断。 通过高可用队列、集群部署和持久化策略&#xff0c;可以保证 消息可靠性、节点容错和持续服务。 本文…

支持向量机:从理论到实践

支持向量机&#xff1a;从理论到实践 文章目录支持向量机&#xff1a;从理论到实践一。理论概述1. 线性可分支持向量机1.1 基本概念与数学形式1.2 函数间隔与几何间隔1.3 间隔最大化与优化问题1.4 拉格朗日对偶理论与求解1.5 支持向量与决策函数2. 近似线性可分数据&#xff08…

LVS与Keepalived详解(二)LVS负载均衡实现实操

文章目录前言一、LVS-DR 模式详解1.1 数据包流向分析1.2 DR 模式的特点二、LVS-DR 集群部署实战2.1 环境准备2.2 配置负载调度器&#xff08;Director Server&#xff09;2.3 配置节点服务器&#xff08;Real Server&#xff09;2.4 测试验证三、前期回顾3.1 LVS 三种工作模式及…

归一化实现原理

归一化&#xff08;Normalization&#xff09;是一种将数据转换到相同尺度的预处理技术&#xff0c;它通常用于让不同特征&#xff08;或数据项&#xff09;具有相同的量纲或范围。在联邦学习中&#xff0c;归一化可以用来处理非独立同分布&#xff08;Non-IID&#xff09;**数…

企业级实战:构建基于Qt、C++与YOLOv8的模块化工业视觉检测系统

一、概述 在追求高效与精密的现代制造业中&#xff0c;自动化光学检测&#xff08;AOI&#xff09;已成为保障产品质量的核心技术。传统的质检流程往往受限于人工效率与主观判断&#xff0c;难以满足大规模、高精度的生产需求。本文旨在研发一套完整的、企业级的工业视觉异常检…

【目标检测】metrice_curve和loss_curve对比图可视化

代码如下&#xff1a; import warnings warnings.filterwarnings(ignore)import os import pandas as pd import numpy as np import matplotlib.pylab as pltpwd os.getcwd()names [model1, model2, model3,ours]plt.figure(figsize(10, 10))plt.subplot(2, 2, 1) for i in …

【LeetCode hot100|Week2】滑动窗口,子串

笔记用于个人复习和巩固&#xff0c;题解非原创&#xff0c;参考LeetCode官方题解以及各个大佬的解法&#xff0c;希望给大家带来帮助&#xff0c;同时笔记也能督促我学习进步 这周主要把滑动窗口和子串的题目刷了一遍 文章目录Week2D1 滑动窗口209. 长度最小的子数组713. 乘积…

vue2纯前端对接海康威视摄像头实现实时视频预览

vue2纯前端对接海康威视摄像头实现实时视频预览一、环境准备二、代码集成1.1 准备webrtcstreamer.js&#xff0c;粘贴即用&#xff0c;不用做任何修改1.2 封装视频组件&#xff0c;在需要视频的地方引入此封装的视频组件即可&#xff0c;也是粘贴即用&#xff0c;注意其中impor…

Android 设置禁止截图和禁止长截图

1.禁止截图 在 Activity 代码中 , 可以在调用 setContentView 函数之前 ,为 Window 窗口对象 设置 LayoutParams.FLAG_SECURE 标志位 , 可以禁止对本界面进行截屏 ,Window 窗口对象 , 可通过 getWindow 方法获取 ,核心代码如下 :getWindow().setFlags(LayoutParams.FLAG_SECUR…

AR 巡检在工业的应用|阿法龙XR云平台

AR 巡检的应用覆盖电力、石油化工、智能制造、轨道交通、冶金等对设备可靠性和安全性要求极高的行业&#xff0c;具体场景包括&#xff1a;电力行业变电站内设备的状态检查&#xff1a;通过 AR 眼镜扫描设备&#xff0c;实时显示设备额定参数、历史故障记录、实时传感器数据&am…

【C++】STL详解(七)—stack和queue的介绍及使用

✨ 坚持用 清晰易懂的图解 代码语言&#xff0c; 让每个知识点都 简单直观 &#xff01; &#x1f680; 个人主页 &#xff1a;不呆头 CSDN &#x1f331; 代码仓库 &#xff1a;不呆头 Gitee &#x1f4cc; 专栏系列 &#xff1a; &#x1f4d6; 《C语言》&#x1f9e9; 《…

深度学习周报(9.8~9.14)

目录 摘要 Abstract 1 LSTM相关网络总结与对比 1.1 理论总结 1.2 代码运行对比 2 量子计算入门 3 总结 摘要 本周首先总结了LSTM、Bi-LSTM与GRU的区别与优缺点&#xff0c;对比了三者实战的代码与效果&#xff0c;还另外拓展了一些循环神经网络变体&#xff08;包括窥视…

Quat 四元数库使用教程:应用场景概述

基础概念 四元数是一个包含四个元素的数组 [x, y, z, w]&#xff0c;其中 x,y,z表示虚部&#xff0c;w 表示实部。单位四元数常用于表示3D空间中的旋转。 1. 创建和初始化函数 create() - 创建单位四元数 应用场景&#xff1a;初始化一个新的四元数对象&#xff0c;通常作为其他…

【Java后端】Spring Boot 多模块项目实战:从零搭建父工程与子模块

如何用 Spring Boot 搭建一个父工程 (Parent Project)&#xff0c;并在其中包含多个子模块 (Module)&#xff0c;适合企业级项目或者需要分模块管理的场景。Spring Boot 多模块项目实战&#xff1a;从零搭建父工程与子模块在日常开发中&#xff0c;我们经常会遇到这样的需求&am…

企业级AI会议系统技术实现:快鹭如何用AI重构会议全流程

摘要 本文深度解析快鹭AI会议系统的核心技术架构&#xff0c;重点探讨其在语音识别、自然语言处理、数据集成和安全防护等方面的技术实现。通过对比传统会议系统的技术痛点&#xff0c;分析快鹭AI如何通过技术创新实现会议筹备时间减少67%、数据调取速度提升100倍的显著效果。…

【CSS学习笔记3】css特性

1css三大特性 1.1层叠性&#xff1a;就近原则&#xff0c;最新定义的样式 1.2继承性&#xff1a;子标签集成父标签的样式&#xff0c;如文本和字号 行高的继承&#xff1a;不加单位指的是当前文字大小的倍数 body {font: 12px/1.5 Microsoft YaHei;color: #be1313;} div {…

[C语言]常见排序算法①

1.排序的概念及常见的排序算法排序在咱们日常生活中十分的常见&#xff0c;就好比是网上购物的时候通常能够选择按照什么排序&#xff0c;比如价格、评论数量、销量等。那么接下来咱们就来了解一些关于排序的概念。排序&#xff1a;所谓排序&#xff0c;就是使一串记录&#xf…

文献阅读笔记:RS电子战测试与测量技术文档

信息来源&#xff1a;罗德与施瓦茨&#xff08;Rohde & Schwarz&#xff09;公司关于电子战&#xff08;Electronic Warfare, EW&#xff09;测试与测量解决方案专业技术文档。 该文档由台湾地区应用工程师Mike Wu撰写&#xff0c;核心围绕电子战基础、雷达系统、实战应用及…