Linux基础开发工具大全
目录
软件包管理器
1>软件包
2>软件生态
3>yum操作
a.查看软件包
b.安装软件
c.卸载软件
4>知识点
vim编辑器
1>基本概念
2>基本操作
3>正常模式命令集
a.模式切换
b.移动光标
c.删除
d.复制
e.替换
f.撤销
g.更改
4>底行模式命令集
a.列出⾏号
b.定位
c.查找
d.退出
e.其它
5>其它实用命令集
6>总结
gcc/g++编译器
1>基本概念
2>编译选项
a.预处理
b.编译
c.汇编
d.链接
3>知识点
4>动静态库
a.库的概念
b.静态库
c.动态库
5>动静态链接
a.静态链接
b.动态链接
6>其它常用选项
自动化创建-make/Makefile
1>基本概念
2>使用和语法
a.简单使用
b.默认扫描
c.伪目标
d.AMC时间
3>推导原则
4>扩展语法
进度条
1>回车与换行
2>行缓冲区
3>倒计时程序
4>进度条代码
版本控制器git
gdb调试器
1>基础知识
2>使用
3>技巧
软件包管理器
1>软件包
为了提高效率,有些人将一些软件(程序的源代码)提前编译好,做成软件包(可以理解成App)放在一个服务器上,通过包管理器(可以理解成应用商店)可以很方便的获取这个编译好的软件包,直接进行安装
yum是Linux下常用的一种包管理器
Ubuntu:主要使用apt作为其包管理器,同样提供了自动解决依赖关系、下载和安装软件包的功能
2>软件生态
Linux下载软件的过程
问题来了,我们的服务器怎么知道,去哪里找软件包?
那是因为在Linux机器上,有对应给yum提供的配置文件!url或者ip地址!
操作系统的好坏评估 --- 生态问题
最根本的是客户群体,因为操作系统针对的客户群体不同,风格以及使用也不同,所以就有了这么多款操作系统(归根结底就是生态的原因)
软件包依赖的问题
yum可以帮助我们完美解决这个问题
国内镜像源
因为大多数软件都是国外的,我国的企业或高校通过购买服务器,将国外的软件包拷贝到国内的服务器,并且提供一个国内的配置文件,后续使用软件只需访问国内的就可以了
切换镜像源,本质就是更改配置文件
下面是我用文心一言生成的切换镜像源的操作,大家也可以尝试使用文心一言或其它工具进行更改配置文件操作
wget获取网页
软件源
配置文件又称为软件源(我们使用的云服务器,内置的配置文件已经是国内的了!)
新开发的软件源要放在扩展软件源,经过时间的验证和认可才可以迁移到稳定软件源
3>yum操作
a.查看软件包
通过yum list命令可以罗列出当前有哪些软件包,使用grep命令筛选我们需要的包
b.安装软件
通过yum命令可以完成gcc-c++的安装,其中包含g++
yum/apt 会自动找到都有哪些软件包需要下载,这时候敲 y 确认安装
出现 complete 字样或中间未发现报错,说明安装完成
注意:
① 安装软件时因为需要向系统目录中写入内容,所以一般需要sudo或者切换到root账户下才能完成
② yum/apt 安装软件只能一个装完了再装另一个,不然会报错
③ Linux一般而言,软件只要安装一次,其它用户都能用!并且是以other的身份使用,毕竟我们是以root身份安装的
c.卸载软件
通过yum命令可以完成对gcc的卸载
在安装或卸载的时候可以加上 -y (sudo yum install/remove -y ...)这样就不需要问我们了,直接安装或卸载
4>知识点
① 操作系统生态问题!
② 什么是OS是好的OS?
③ 重新理解Centos vs Ubnutu vs kail ...
vim编辑器
vi 和 vim 都是多模式编译器,不同的是vim是vi的升级版本,它不仅兼容vi的所有指令,而且还有一些新的特性在里面
1>基本概念
vim有很多种模式,这里我介绍基础且常用的三种模式
① 正常/普通/命令模式(Normal mode)
功能:控制屏幕光标的移动,字符、字或行的删除,移动复制某区段及进入插入模式或末行模式
② 插入模式(Insert mode)
功能:只有在Insert mode下,才可以做文字输入
③ 末行模式(last line mode)
功能:文件保存或退出,也可以进行文件替换,找字符串,列出行号等操作
2>基本操作
① 进入vim全屏幕编辑画面 | 输入vim及文件名称(vim test.c) |
---|---|
② [正常模式]切换至[插入模式] | 「 a 」「 i 」「 o 」 |
③ [插入模式]切换至[正常模式] | 按⼀下「ESC」键切换回[正常模式] |
④ [正常模式]切换至[底行模式] | 「shirt + ;」---> 本质就是输入「 : 」 |
⑤ [底行模式]切换至[正常模式] | 按⼀下「ESC」键切换回[正常模式] |
⑥ 退出vim及保存文件,在[正常模式]下切换至末行模式 | |
输入 「w」 | 保存当前文件 |
输入 「wq」 | 存盘并退出vim |
输入 「q」 | 不存盘强制退出vim |
输入 「wq!」 | 存盘并强制退出vim |
当我们不知道此时处于什么模式时,直接ESc切换回正常模式就可以了
3>正常模式命令集
a.模式切换
从正常模式切换至插入模式 | |
---|---|
「i」 | 从光标当前位置开始输入文件 |
「a」 | 从目前光标所在位置的下一个位置开始输入文字 |
「o」 | 插入新的一行,从行首开始输入文字 |
从插入模式切换至正常模式 | |
「ESc」 | 切换回正常模式 |
「shirt +zz」 | 保存文件并退出vim |
b.移动光标
「h」、「j」、「k」、「l」 | 分别控制光标左、下、上、右移一格 |
---|---|
「gg」 | 进入文本开始 |
「shirt + g」->「G」 | 进入文本末端 |
「n + gg」 | 进入文本第n行 |
「shirt + 4」->「$」 | 移动到光标所在行的行尾 |
「shirt + 6」->「^」 | 移动到光标所在行的行首 |
「w」 | 光标跳到下个单词的开头 |
「e」 | 光标跳到下个单词的尾端 |
「b」 | 光标回到上个单词的开头 |
「n + l」 | 光标移到该行的第n个位置 |
「ctrl + d」 | 屏幕往前移动半页 |
「ctrl + u」 | 屏幕往后移动半页 |
「ctrl + f」 | 屏幕往前移动一页 |
「ctrl + b」 | 屏幕往后移动一页 |
c.删除
「x」 | 每按⼀次删除光标所在位置的⼀个字符 |
---|---|
「n + x」 | 删除光标所在位置后面的n个字符(包括自己) |
「shirt + x」->「X」 | 每按⼀次删除光标所在位置的前⾯⼀个字符 |
「n + X」 | 删除光标所在位置前⾯的n个字符(包括自己) |
「dd」 | 剪切/删除光标所在⾏ |
「n + dd」 | 从光标所在⾏开始剪切/删除n⾏ |
d.复制
「yw」 | 将光标所在之处到字尾的字符复制到缓冲区中 |
---|---|
「n + yw」 | 复制n个字到缓冲区 |
「yy」 | 复制光标所在⾏到缓冲区 |
「n + yy」 | 拷⻉从光标所在⾏往下数n⾏⽂字 |
「p」 | 将缓冲区内的字符贴到光标所在位置 |
「n + p」 | 粘贴到当前行的下n行 |
注意:所有与 y 有关的复制命令都必须与 p 配合才能完成复制与粘贴功能
e.替换
「r」 | 替换光标所在处的字符 |
---|---|
「n + r」 | 替换光标所在处及后n个字符 |
「shirt + r」->「R」 | 替换光标所到之处的字符,直到按下「ESC」键为⽌ |
「shirt + `」->「~」 | 快速大小写切换 |
f.撤销
「u」 | 误执⾏⼀个命令时,u可以回到上⼀个操作 |
---|---|
「ctrl + r」 | 撤销的恢复 |
注意:只要不退出vim,都可以撤销!
g.更改
「cw」 | 更改光标所在处的字到字尾处 |
---|---|
「c + n + w」 | 更改光标所在处及后面n个字 |
4>底行模式命令集
a.列出⾏号
「set nu」 | 在⽂件中的每⼀⾏前⾯列出⾏号 |
---|
b.定位
「n」 | 在冒号后输⼊⼀个数字,再按回⻋键就会跳到该⾏了 |
---|
c.查找
「/关键字」 | 先按「/」键,再输⼊您想寻找的字符,如果第⼀次找的关键字不是您想要的,可以⼀直按「n」会往后寻找到您要的关键字为⽌ |
---|---|
「?关键字」 | 先按「?」键,再输⼊您想寻找的字符,如果第⼀次找的关键字不是您想要的,可以⼀直按「n」会往前寻找到您要的关键字为⽌ |
d.退出
「q」 | 退出vim |
---|---|
「q!」 | 强制退出vim |
「w」 | 将⽂件保存起来 |
「w!」 | 强制将⽂件保存起来并退出vim |
e.其它
「!command」 | 输入(!指令),会先执行这条指令,按任意键再返回来,这样可以方便调试 |
---|---|
「vs (other)」 | 这里的other指的是其它文件,实现分屏操作 |
「ctrl + ww」 | 在分屏时让光标移动到任意屏幕 |
注意:光标在哪个终端,执行的就是哪个终端
5>其它实用命令集
① 批量化注释:ctrl+v --> hjkl --> shirt+i == I --> ESc
解释:ctrl+v是进入视图模式,hjkl选择需要注释的行,shirt+i是进入插入模式,最后ESc退出视图模式(退出后才会显示注释的全部内容)
② 批量化注释:ctrl+v --> hjkl --> d
解释:ctrl+v是进入视图模式,hjkl选择需要去注释的内容,d是删除该内容
③ 替换(底行模式):%s/printf/print/g
解释:这条指令的意思是将全部的printf换成print,g代表的意思是全部,注意是后替换前
④ 快速定位:当我们编译报错时,根据报错提示知道大概哪里错误,这时就可以输入 vim test.c +13
解释:这条指令的意思是进入vim之后光标直接定位到第13行这个位置
⑤ 便捷指令:!commond
解释:这条指令的意思是快速执行历史命令,例如gcc test.c -o test,我修改了一下test.c的内容,此时 !g 就可以快速帮我再次执行这条指令;同样 !l 可以快速帮我执行 ll 这条指令
6>总结
gcc/g++编译器
1>基本概念
预处理 | 进⾏宏替换/去注释/条件编译/头⽂件展开等 |
---|---|
编译 | ⽣成汇编 |
汇编 | ⽣成机器可识别代码 |
链接 | ⽣成可执⾏⽂件或库⽂件 |
2>编译选项
格式:gcc [选项] 要编译的文件 [选项] [目标文件]
a.预处理
① 预处理功能主要包括宏定义,⽂件包含,条件编译,去注释等
② 预处理指令是以#号开头的代码⾏
③ -E 选项是让 gcc 在预处理结束后停⽌编译过程
④ -o 选项是指⽬标⽂件,".i" ⽂件为已经预处理的C原始程序
b.编译
① 在这个阶段中,gcc ⾸先要检查代码的规范性、是否有语法错误等,以确定代码的实际要做的⼯作,在检查⽆误后,gcc 把代码翻译成汇编语⾔
② -S 选项是只进⾏编译⽽不进⾏汇编,⽣成汇编代码
c.汇编
① 汇编阶段是把编译阶段⽣成的“.s”⽂件转成⽬标⽂件
② -c 选项是可以看到汇编代码已转化为“.o”的⼆进制⽬标代码
d.链接
① 在成功编译之后,就进⼊了链接阶段
3>知识点
① 为什么要编译、汇编?
减少语言开发的成本
② 如何理解条件编译?
通过条件编译就可以只需要维护一份代码,实现不同版本(例如免费版、校园版、专业版...)
4>动静态库
⼀般我们的云服务器,C/C++的静态库并没有安装,可以采⽤如下⽅法安装(我这里是安装了的,所以显示是有这个库的)
yum install glibc-static libstdc++-static -y
a.库的概念
我们的C程序中,并没有定义 “printf” 的函数实现,且在预编译中包含的 “stdio.h” 中也只有该函数的声明,⽽没有定义函数的实现,那么是在哪⾥实现 “printf” 函数的呢?
答案是系统把这些函数实现都被做到名为 libc.so.6 的库⽂件中去了,在没有特别指定时,gcc 会到系统默认的搜索路径 “/usr/lib” 下进⾏查找,也就是链接到 libc.so.6 库函数中去,这样就能实现函数 “printf” 了,⽽这也就是链接的作⽤
b.静态库
静态库是指编译链接时,把库⽂件的代码全部加⼊到可执⾏⽂件中,因此⽣成的⽂件⽐较⼤,但在运⾏时也就不再需要库⽂件了(其后缀名⼀般为 “.a” )
c.动态库
动态库与之相反,在编译链接时并没有把库⽂件的代码加⼊到可执⾏⽂件中,⽽是在程序执⾏时由运⾏时链接⽂件加载库,这样可以节省系统的开销。(其后缀名⼀般为 “.so”)
Linux | 动态库XXX.so, 静态库XXX.a |
---|---|
Windows | 动态库XXX.dll, 静态库XXX.lib |
5>动静态链接
gcc默认⽣成的可执行程序是动态链接的!(这点可以通过 file 命令验证)
a.静态链接
在我们的实际开发中,不可能将所有代码放在⼀个源⽂件中,所以会出现多个源⽂件,⽽且多个源⽂件之间不是独⽴的,⽽会存在多种依赖关系,如⼀个源⽂件可能要调⽤另⼀个源⽂件中定义的函数,但是每个源⽂件都是独⽴编译的,即每个.c⽂件会形成⼀个.o⽂件,为了满⾜前⾯说的依赖关系,则需要将这些源⽂件产⽣的⽬标⽂件进⾏链接,从⽽形成⼀个可以执⾏的程序
优点 | 缺点 |
---|---|
在可执⾏程序中已经具备了所有执⾏程序所需要的任何东西,在执⾏的时候运⾏速度快 | 浪费空间:因为每个可执⾏程序中对所有需要的⽬标⽂件都要有⼀份副本,所以如果多个程序对同⼀个⽬标⽂件都有依赖,如多个程序中都调⽤了printf()函数,则这多个程序中都含有printf.o,所以同⼀个⽬标⽂件都在内存存在多个副本 |
更新⽐较困难:因为每当库函数的代码修改了,这个时候就需要重新进⾏编译链接形成可执⾏程序 |
b.动态链接
基本思想是把程序按照模块拆分成各个相对独⽴部分,在程序运⾏时才将它们链接在⼀起形成⼀个完整的程序,⽽不是像静态链接⼀样把所有程序模块都链接成⼀个单独的可执⾏⽂件(并且动态链接远⽐静态链接要常⽤得多)
总结:
① 动态库是共享的,所以不能丢失,一旦丢失,所有依赖动态库的程序都会运行出错
② 静态链接是把我们要的库方法实现,直接拷贝到我们的可执行程序中
6>其它常用选项
-E | 只激活预处理,这个不⽣成⽂件,需要我们把它重定向到⼀个输出⽂件⾥⾯ |
---|---|
-S | 编译到汇编语⾔不进⾏汇编和链接 |
-c | 编译到⽬标代码 |
-o | ⽂件输出到⽂件 |
-static | 对⽣成的⽂件采⽤静态链接 |
-g | ⽣成调试信息(GNU 调试器可利⽤该信息) |
-w | 不⽣成任何警告信息 |
-Wall | ⽣成所有警告信息 |
-shared | 尽量使⽤动态库,所以⽣成⽂件⽐较⼩,但是需要系统有动态库 |
-O0、-O1、-O2、-O3 | 编译器的优化选项的4个级别,-O0表⽰没有优化,-O1为缺省值,-O3优化级别最⾼ |
自动化创建-make/Makefile
1>基本概念
① ⼀个⼯程中的源⽂件不计数,其按类型、功能、模块分别放在若⼲个⽬录中,makefile定义了⼀系列的规则来指定,哪些⽂件需要先编译,哪些⽂件需要后编译,哪些⽂件需要重新编译,甚⾄于进⾏更复杂的功能操作
② makefile带来的好处就是⸺“⾃动化编译”,⼀旦写好,只需要⼀个make命令,整个⼯程完全⾃动编译,极⼤的提⾼了软件开发的效率
③ make是⼀个命令⼯具,是⼀个解释makefile中指令的命令⼯具,⼤多数的IDE都有这个命令
④ make是⼀条命令,makefile是⼀个⽂件,两个搭配使⽤,完成项⽬⾃动化构建!
2>使用和语法
a.简单使用
b.默认扫描
c.伪目标
项目清理
① ⼯程是需要被清理的
② 像clean这种,没有被第⼀个⽬标⽂件直接或间接关联,那么它后⾯所定义的命令将不会被⾃动执⾏,不过我们可以显⽰ “make clean” 执⾏,以此来清除所有的⽬标⽂件,以便重编译
③ ⼀般我们这种clean的⽬标⽂件,都将它设置为伪⽬标,⽤ .PHONY 修饰(伪⽬标的特性是总是被执⾏的!)
d.AMC时间
没有 .PHONY 修饰的目标文件为什么第二次编译就不可以,是如何做到的?其实主要是为了提高编译效率
总结:
① Modify: 内容变更,时间更新
② Change:属性变更,时间更新
③ Access:常指的是⽂件最近⼀次被访问的时间(在Linux的早期版本中,每当⽂件被访问时,其atime都会更新,这种机制会导致⼤量的IO操作)
④ .PHONY:让make忽略源⽂件和可执⾏⽬标⽂件的M时间对⽐
3>推导原则
下面是推导原则
在默认的⽅式下,make是如何⼯作的?
make会在当前⽬录下找名字叫“Makefile”或“makefile”的⽂件 |
---|
如果找到,它会找⽂件中的第⼀个⽬标⽂件(target),在上⾯的例⼦中,他会找到 myproc 这个⽂件,并把这个⽂件作为最终的⽬标⽂件 |
如果 myproc ⽂件不存在,或是 myproc 所依赖的后⾯的 myproc.o ⽂件的⽂件修改时间要⽐ myproc 这个⽂件新(可以⽤ touch 测试),那么它就会执⾏后⾯所定义的命令来⽣成 myproc 这个⽂件 |
如果 myproc 所依赖的 myproc.o ⽂件不存在,那么 make 会在当前⽂件中找⽬标为 myproc.o ⽂件的依赖性,如果找到则再根据那⼀个规则⽣成 myproc.o ⽂件。(这有点像⼀个堆栈的过程) |
当然,我们的C⽂件和H⽂件肯定是存在的,于是 make 会⽣成 myproc.o ⽂件,然后再⽤ myproc.o ⽂件声明 make 的终极任务,也就是执⾏⽂件了 |
这就是整个make的依赖性,make会⼀层⼜⼀层地去找⽂件的依赖关系,直到最终编译出第⼀个⽬标⽂件 |
在找寻的过程中,如果出现错误,⽐如最后被依赖的⽂件找不到,那么make就会直接退出,并报错,⽽对于所定义的命令的错误,或是编译不成功,make根本不理 |
make只管⽂件的依赖性,意思就是如果在我找了依赖关系之后,冒号后⾯的⽂件还是不在,那么对不起,我就不⼯作了 |
下面是推导过程
4>扩展语法
BIN=proc.exe # 定义变量
CC=gcc
#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) $@ $^ # $@:代表目标文件名 $^: 代表依赖文件列表@echo "linking ... $^ to $@"
%.o:%.c # %.c 展开当前目录下所有的.c %.o: 同时展开同名.o@$(CC) $(FLAGS) $< # %<: 对展开的依赖.c文件,⼀个⼀个的交给gcc@echo "compling ... $< to $@" # @:不回显命令.PHONY:clean
clean:$(RM) $(OBJ) $(BIN) # $(RM): 替换,用变量内容替换它.PHONY:test
test:@echo $(SRC)@echo $(OBJ)
注意:快速创建/删除文件
touch 文件名{1..数量}后缀
rm 文件名{1..数量}后缀
进度条
1>回车与换行
回车 '/r' :将光标或打印位置移至当前行开头,不换到下一行
换行 '/n':将光标或打印位置移至下一行行首,不改变水平位置
2>行缓冲区
#include <stdio.h>
#include <unistd.h>int main()
{// printf("hello tianci\n");// printf("hello tianci");// fflush(stdout);sleep(3); return 0;
}
3>倒计时程序
#include <stdio.h>
#include <unistd.h>
int main()
{ int cnt = 10;while(cnt >= 0) { printf("%-2d\r", cnt); fflush(stdout); cnt--; sleep(1); } printf("\n");return 0;
}
4>进度条代码
先小试牛刀,可以尝试简单编写,没有问题再继续
接下来就是进度条代码的编写
先说一下设计的想法,就是预留100个字符,每走过的位置留下=,右边第一个[]显示百分比(完成了多少),第二个[]显示标识符(一直旋转直到进度条运行结束)
Makefile
BIN=process #程序名和我们的要实现的功能有关,这就有意义了
# SRC=$(shell ls *.c)
SRC=$(wildcard *.c)
OBJ=$(SRC:.c=.o)
CC=gcc
RM=rm -f$(BIN):$(OBJ)@$(CC) $^ -o $@@echo "链接 $^ 成 $@"%.o:%.c@$(CC) -c $<@echo "编译... $< 成 $@".PHONY:clean
clean:@$(RM) $(OBJ) $(BIN).PHONY:test
test:@echo $(BIN)@echo $(SRC)@echo $(OBJ)
process.h
#pragma once
#include <stdio.h>// v1
void process();// v2
void FlushProcess(const char*, double total, double current);
注意:头文件中的参数名和实现文件中的参数名可以不一致(头文件中的参数名主要是为了提供可读性,而实现文件中的参数名是实际使用的变量名,只要参数的类型和顺序保持一致就可以了)
process.c
#include "process.h"
#include <string.h>
#include <unistd.h>#define SIZE 101
#define STYLE '='// v2:根据进度,动态刷新一次进度条
void FlushProcess(const char* tips, double total, double current)
{const char* lable = "|/-\\";size_t len = strlen(lable);static int index = 0;char buffer[SIZE];memset(buffer, 0, sizeof(buffer));double rate = current * 100.0 / total;int num = (int)rate;int i = 0;for (; i < num; i++)buffer[i] = STYLE;printf("%s...[%-100s][%.1lf%%][%c]\r", tips, buffer, rate, lable[index++]);fflush(stdout);index %= len;if (num >= 100) printf("\n");
}// v1:展示进度条基本功能
void process()
{int rate = 0;char buffer[SIZE];memset(buffer, 0, sizeof(buffer));const char* lable = "|/-\\";size_t len = strlen(lable);
}
注意:
① 当网速为0时,进度条虽然停止,但是lable还在一直动,可以知道进度条还在运行,而是网速不行,所以这里的lable就起到了标识符的作用
② memset是因为我想将整个buffer里面都设置为0,后面要增加内容直接增加就行了
③ -100%s --> 100是为了占位置,让右括号直接定位到结尾,不用跟着跑,负号是为了让字符左对齐
④ %% 输出为一个%,//输出为一个/
main.c
#include "process.h"
#include <unistd.h>
#include <time.h>
#include <stdlib.h>typedef void (*call_t)(const char*, double, double);double total = 1024.0;
// double speed = 1.0;
double speed[] = {1.0, 0.5, 0.3, 0.02, 0.1, 0.01}; // 模拟网速// 回调函数
void DownLoad(int total, call_t cb)
{srand(time(NULL));double current = 0.0;while (current <= total){cb("下载中", total, current); // 进行回调if (current >= total) break;int random = rand() % 6;usleep(5000); // 充当下载数据current += speed[random];if (current >= total)current = total;}
}void uploadLoad(int total, call_t cb)
{srand(time(NULL));double current = 0.0;while (current <= total){cb("上传中", total, current); // 进行回调if (current >= total) break;int random = rand() % 6;usleep(5000); // 充当下载数据current += speed[random];if (current >= total)current = total;}
}int main()
{DownLoad(1024.0, FlushProcess);printf("download 1024.0MB done\n");DownLoad(512.0, FlushProcess);printf("download 512.0MB done\n");DownLoad(256.0, FlushProcess);printf("download 256.0MB done\n");DownLoad(128.0, FlushProcess);printf("download 128.0MB done\n");DownLoad(64.0, FlushProcess);printf("download 64.0MB done\n");uploadLoad(500.0, FlushProcess);// process();return 0;
}
版本控制器git
为了能够更⽅便我们管理这些不同版本的⽂件,便有了版本控制器。所谓的版本控制器,就是能让你了解到⼀个⽂件的历史,以及它的发展过程的系统(通俗的讲就是⼀个可以记录⼯程的每⼀次改动和版本迭代的⼀个管理系统,同时也⽅便多⼈协同作业)
⽬前最主流的版本控制器就是 Git,它可以控制电脑上所有格式的⽂件,最重要的是可以帮助我们管理软件开发项⽬中的源代码⽂件!
// 安装
sudo yum install git
这里有几个地方需要注意:
① git提交的时候,只会提交变化的部分!
② 首次使用git需要设置名字和邮箱(有提示,git config --global user.name/user.email "...")
③ git版本管理,只进行管理源文件
④ .gitignore:需要忽略的特定后缀的文件列表(vim .gitignore 修改配置后立即生效)
⑤ 远端仓库,相比较与任何人,都是最新的(大胆pull,放心!)
⑥ 为什么要产生冲突?那是因为想提醒本地用户,你该和远程仓库进行同步了(可以理解为一种保护机制)
gdb调试器
1>基础知识
2>使用
先来看一下简单的使用
cgdb调试起来会清晰一点,指令和gdb是一样的
sudo yum install -y cgdb
总结:
开始:gdb binFile
退出:ctrl + d 或 quit 调试命令
命令 | 作⽤ |
---|---|
list/l | 显⽰源代码,从上次位置开始,每次列出10⾏ |
list/l 函数名 | 列出指定函数的源代码 |
list/l ⽂件名:⾏号 | 列出指定⽂件的源代码 |
r/run | 从程序开始连续执⾏ |
n/next | 单步执⾏,不进⼊函数内部 |
s/step | 单步执⾏,进⼊函数内部 |
break/b [⽂件名:]⾏号 | 在指定⾏号设置断点 |
break/b 函数名 | 在函数开头设置断点 |
info break/b | 查看当前所有断点的信息 |
finish | 执⾏到当前函数返回,然后停⽌ |
print/p 表达式 | 打印表达式的值 |
p 变量 | 打印指定变量的值 |
set var 变量=值 | 修改变量的值 |
continue/c | 从当前位置开始连续执⾏程序 |
delete/d breakpoint | 删除所有断点 |
delete/d breakpoints n | 删除序号为n的断点 |
disable breakpoints | 禁⽤所有断点 |
enable breakpoints | 启⽤所有断点 |
info/i breakpoints | 查看当前设置的断点列表 |
display 变量名 | 跟踪显⽰指定变量的值(每次停⽌时) |
undisplay 编号 | 取消对指定编号的变量的跟踪显⽰ |
until X⾏号 | 执⾏到指定⾏号 |
backtrace/bt | 查看当前执⾏栈的各级函数调⽤及参数 |
info/i locals | 查看当前栈帧的局部变量值 |
quit | 退出GDB调试器 |
3>技巧
watch
执⾏时监视⼀个表达式(如变量)的值。如果监视的表达式在程序运⾏期间的值发⽣变化,gdb 会暂停程序的执⾏,并通知使⽤者
注意:如果你有⼀些变量不应该修改,但是你怀疑它修改导致了问题,你可以watch它,如果变化了,就会通知你
set val
更改⼀下标志位
条件断点
注意:
① 新增:b ⾏号/⽂件名:⾏号/函数名 if i == 30(条件)
② 给已有断点追加:condition 2 i==30, 其中2是已有断点编号,没有if
③ cgdb分配操作按ESc进入代码屏,输入i回到cgdb屏
本篇文章到这里就结束啦,希望这些内容对大家有所帮助!
下篇文章见,希望大家多多来支持一下!
感谢大家的三连支持!
相关文章:

Linux基础开发工具大全
目录 软件包管理器 1>软件包 2>软件生态 3>yum操作 a.查看软件包 b.安装软件 c.卸载软件 4>知识点 vim编辑器 1>基本概念 2>基本操作 3>正常模式命令集 a.模式切换 b.移动光标 c.删除 d.复制 e.替换 f.撤销 g.更改 4>底行模式命令…...
【C/C++】C++中引用类型私有成员的设计与应用
文章目录 C中引用类型私有成员的设计与应用核心意义典型使用场景1. 依赖注入(Dependency Injection)2. 避免拷贝开销3. 实现不可变设计4. 接口约束 注意事项1. 生命周期管理2. 构造函数的强制性3. 不可重新绑定4. 与多态的结合 对比指针的优缺点总结 C中…...

网页工具-OTU/ASV表格物种分类汇总工具
AI辅助下开发了个工具,功能如下,分享给大家: 基于Shiny开发的用户友好型网页应用,专为微生物组数据分析设计。该工具能够自动处理OTU/ASV_taxa表格(支持XLS/XLSX/TSV/CSV格式),通过调用QIIME1&a…...
存储器上如何存储1和0
在计算机存储器中,数据最终以**二进制形式(0和1)**存储,这是由硬件特性和电子电路的物理特性决定的。以下是具体存储方式的详细解析: 一、存储的物理基础:半导体电路与电平信号 计算机存储器(…...

2025第三届盘古初赛(计算机部分)
前言 比赛的时候时间不对,打一会干一会,导致比赛时候思路都跟不上,赛后简单复现一下,希望大家批批一下 计算机取证 1、分析贾韦码计算机检材,计算机系统Build版本为?【标准格式:19000】 183…...

【源码级开发】Qwen3接入MCP,企业级智能体开发实战!
Qwen3接入MCP智能体开发实战(上) 一、MCP技术与Qwen3原生MCP能力介绍 1.智能体开发核心技术—MCP 1.1 Function calling技术回顾 如何快速开发一款智能体应用,最关键的技术难点就在于如何让大模型高效稳定的接入一些外部工具。而在MCP技术…...
文本数据词汇级增强
import nltkfrom nltk.corpus import wordnetfrom nltk.tokenize import word_tokenizeimport random# nltk.download(wordnet)# nltk.download(punkt)def get_synonyms(word):"""获取单词的同义词列表"""synonyms []for syn in wordnet.synset…...

基于EFISH-SCB-RK3576/SAIL-RK3576的消防机器人控制器技术方案
(国产化替代J1900的应急救援智能化解决方案) 一、硬件架构设计 极端环境防护系统 防爆耐高温设计: 采用陶瓷纤维复合装甲(耐温1200℃持续1小时),通过GB 26784-2023消防设备防爆认证IP68防护等级…...

微信小程序:封装request请求、解决请求路径问题
一、创建文件 1、创建请求文件 创建工具类文件request.js,目的是用于发送请求 二、js接口封装 1、写入接口路径 创建一个变量BASE_URL专门存储api请求地址 2、获取全局的token变量 从缓存中取出token的数据 3、执行请求 (1)方法中接收传递的参数 function request(url,…...

【技术原理】ELK技术栈的历史沿革与技术演进
一、起源与早期发展(2010-2015) ELK技术栈的诞生源于互联网时代对海量日志处理的迫切需求。2010年,Elasticsearch作为基于Apache Lucene的分布式搜索引擎问世,其核心能力包括实时全文检索、倒排索引和分片存储机制,填补…...
point3d 视野朝向设置
这里写自定义目录标题 point3d 视野朝向设置三维相机朝向的直观理解 point3d 视野朝向设置 open3d.visualization.Visualizer 中的 get_view_control() 方法返回一个 ViewControl 对象,用来控制 3D 可视化窗口中的相机视角。通过这个对象可以设置视角朝向ÿ…...
windows服务器下自启动后台运行python脚本
前言 最近有个需求,在windows下根据系统的cpu核数,运行python脚本,记录下在windows注册服务,后台运行python脚本 目录 前言✅ 一、目录结构(示例)✅ 二、manager.py(启动与 CPU 数相同的子进程…...
【Elasticsearch】flattened`类型在查询嵌套数组时可能返回不准确结果的情况
好的!为了更清楚地说明flattened类型在查询嵌套数组时可能返回不准确结果的情况,我们可以通过一个具体的例子来展示。这个例子将展示如何在文档中没有完全匹配的嵌套对象时,flattened类型仍然可能返回该文档。 示例文档结构 假设你有以下文…...
Mysql、Oracle、Sql Server、达梦之间sql的差异
1:分页查询 Sql Server: <bind name"startRow" value"(page - 1) * limit 1"/> <bind name"endRow" value"page * limit"/> SELECT *FROM (SELECT ROW_NUMBER() OVER (<if test"sortZd!…...

记录算法笔记(2025.5.15)将有序数组转换为二叉搜索树
给你一个整数数组 nums ,其中元素已经按 升序 排列,请你将其转换为一棵 平衡 二叉搜索树。 示例 1: 输入:nums [-10,-3,0,5,9] 输出:[0,-3,9,-10,null,5] 解释:[0,-10,5,null,-3,null,9] 也将被视为正确…...
数学复习笔记 11
前言 向量开始。 矩阵的秩 k 阶子式。从这个概念开始复习。考虑 k 阶子式是否为零,具体是多少我们不在乎,我们只在乎 k 阶子式是否为零。把一套资料复习好就好了。 秩的计算 初等变换秩不发生改变。要么初等变换,要么行列式。用行列式需…...

Kubernetes 运维操作手册:从 etcd 快照进行精确恢复
1 5 步实现 etcd 精确恢复 将快照恢复到本地 etcd 数据目录。使用恢复的数据启动本地 etcd 实例。使用 etcdctl 查询特定键(例如,ConfigMap)。使用 auger 解码以提取干净的 YAML。使用 kubectl 申请恢复到您的实时集群。 本指南将指导您从 et…...

云轴科技ZStack官网上线Support AI,智能助手助力高效技术支持
5月16日,云轴科技ZStack在官网(www.zstack.io)正式上线ZStack Support AI智能助手。该系统是ZStack应用人工智能于技术支持服务领域的重要创新,基于自研ZStack AIOS平台智塔及LLMOPS技术打造。 ZStack Support AI定位为智能客服&…...

UE5中制作动态数字Decal
在进行城市道路编辑时,经常需要绘制人行道、交通标志、停车线等路面元素。如果能够使用具有动态修改功能的 Decal(贴花),将大大提升编辑效率和灵活性。接下来讲解如何制作。 1.首先准备一张包含所需元素的Texture,这里…...

【踩坑】修复Cloudflare的Origin Rules端口重定向不生效
转载请注明出处:小锋学长生活大爆炸[xfxuezhagn.cn] 如果本文帮助到了你,欢迎[点赞、收藏、关注]哦~ 网上没人说,目前我是通过以下两种方式成功将二级域名映射到指定端口的。关于如何映射,网上教程很多,这里只说不生效…...

2025 年十大网络安全预测
随着我们逐步迈向 2026 年,网络安全领域正处于一个关键的转折点,技术创新与数字威胁以前所未有的复杂态势交织在一起。 地缘政治环境进一步加剧了这些网络安全挑战,国际犯罪组织利用先进的技术能力来追求战略目标。 人工智能在这一不断演变…...
JS手写代码篇---手写 instanceof 方法
2、手写 instanceof 方法 instancecof用于检测一个对象是否是某个构造函数的实例。它通常用于检查对象的类型,尤其是在处理继承关系时。 eg: const arr [1,2,3,4,5]console.log(arr instanceof Array); // trueconsole.log(arr instanceof Object); // true那这是…...
STM32硬件I2C驱动OLED屏幕
本文基于STM32硬件I2C驱动SSD1306 OLED屏幕,提供完整的代码实现及关键注意事项,适用于128x32或128x64分辨率屏幕。代码通过模块化设计,支持显示字符、数字、汉字及位图,并优化了显存刷新机制。 零、完整代码 完整代码: 1&#x…...

紫外相机工作原理及可应用范围
紫外相机是一种利用紫外线(UV)波段进行成像的设备,紫外线可用于机器视觉应用中,以检测使用可见光无法检测到的特征,工业上使用最常见的紫外波长是365nm和395nm。紫外相机通常用于高分辨率视频显微镜、电晕检测、半导体…...

【虚幻引擎】UE5独立游戏开发全流程(商业级架构)
本套课程我将会讲解一下知识 1.虚幻引擎的常用功能节点、模块包含但不限于动画模块、UI模块、AI模块、碰撞模块、伤害模块、背包模块、准心模块、武器模块、可拾取物品模块、死亡等模块。 2.整个游戏的设计思路(游戏架构),本套教程讲解了如…...

嵌入式单片机中STM32F1演示寄存器控制方法
该文以STM32F103C8T6为示例,演示如何使用操作寄存器的方法点亮(关闭LED灯),并讲解了如何调试,以及使用宏定义。 第一:操作寄存器点亮LED灯。 (1)首先我们的目的是操作板子上的LED2灯,对其实现点亮和关闭操作。打开STM32F103C8T6的原理图,找到LED2的位置。 可以看到…...

spark-cache模式
一、RDD持久化 1.什么时候该使用持久化(缓存) 2. RDD cache & persist 缓存 3. RDD CheckPoint 检查点 4. cache & persist & checkpoint 的特点和区别 特点 区别 二、cache & persist 的持久化级别及策略选择 Spark的几种持久化…...

架构思维:通用架构模式_系统监控的设计
文章目录 引言什么是监控三大常见监控类型1. 次数监控2. 性能监控3. 可用率监控 落地监控1. 服务入口2. 服务内部3. 服务依赖 监控时间间隔的取舍小结 引言 架构思维:通用架构模式_从设计到代码构建稳如磐石的系统 架构思维:通用架构模式_稳如老狗的SDK…...
Laravel 参数验证工具
Laravel 提供了内置的参数验证工具,可以让你定义参数需满足的规则,程序自动进行验证。如果验证成功,程序继续运行;如果失败,则自动返回响应并显示失败原因。 具体实现方式如下: 1. 创建自定义请求类 你可…...

InfluxDB 2.7 连续查询实战指南:Task 替代方案详解
InfluxDB 2.7 引入了 Task 功能,作为连续查询(CQ)的现代替代方案。本文详细介绍了如何使用 Task 实现传统 CQ 的功能,包括语法解析、示例代码、参数对比以及典型应用场景。通过实际案例和最佳实践,帮助开发者高效迁移并…...