我是贝尔格里尔斯,我要向你展示如何入门并熟练掌握世界上最难的操作系统之一linux,这里遍布着数不清的指令,以及完全脱离图形化的界面,没有高超的学习技巧,甚至连一秒都坚持不下去--基础开发
孩子们,在踏上linux的征服之旅上,你必须跨过的门槛就是学会使用yum,vim,以及makefile等开发工具的使用,没有这些基础的生存工具,那完全脱离图形化的界面会击溃你,所以让我们赶紧行动起来吧。
1. yum的具体操作
1.1 软件包
在Linux下安装软件,一个通常的办法是下载程序的源代码,并进行编译,得到可执行程序。
但是这样太麻烦了,于是有些人把一些常用的软件提前编译好,做成软件包(可以理解成Windows上的安装程序)放在一个服务器上,通过包管理器可以很方便地获取到这个编译好的软件包,直接进行安装。
软件包和软件包管理器,就好比“App”和“应用商店”这样的关系。
yum (Yellow dog Updater, Modified) 是 Linux 下非常常用的一种包管理器,主要应用在 Fedora、RedHat 和 CentOS 等发行版上。使用 yum 可以方便地安装、更新和删除软件包,就类似于我们使用应用宝来管理手机中的app一样。
1.2 linux的生态
为什么这么多人选择使用linux?为什么我们国家不开发属于自己的的操作系统?最高关键的问题就是在于生态!
操作系统是给我们程序员去使用,使用的人多了,才有人愿意去为其发现bug,修理bug,完善功能,大家为爱发电之后,操作系统的功能越来越完善了,才会有更多人去使用。
linux是国外的开发工具,使用由于一些不可抗的因素,我们无法安装国外的软件包。我们使用的是各大高校在国内所建立的镜像网站的资源。
1.3 yum的具体操作
1.3.1 查看软件包
yum list 命令可以罗列出当前⼀共有哪些软件包.由于包的数量很多,我们使用管道操作加grep命令筛选出我们关注的包。
• 软件包名称: 主版本号.次版本号.源程序发行号-软件包的发行号.主机平台.cpu架构.
• "x86_64" 后缀表示64位系统的安装包, "i686" 后缀表示32位系统安装包. 选择包时要和系统匹配.
• "el7" 表示操作系统发行版的版本. "el7" 表示的是 centos7/redhat7. "el6" 表示 centos6/redhat6.
• 最后一列, base 表示的是"软件源"的名称, 类似于"小米应用商店", "华为应用商店"这样的概念.
1.3.2 安装软件
通过yum,我们可以通过很简单的⼀条命令完成gcc的安装.
# Centos
$ sudo yum install -y lrzsz
注意事项:
• 安装软件时由于需要向系统⽬录中写⼊内容,⼀般需要sudo或者切到root账⼾下才能完成.
• yum/apt安装软件只能⼀个装完了再装另⼀个.正在yum/apt安装⼀个软件的过程中,如果再尝试⽤ yum/apt安装另外⼀个软件,yum/apt会报错.
1-3-3 卸载软件
# Centos
sudo yum remove [-y] lrzsz
1.4 安装源
#Cetnos
$ ll /etc/yum.repos.d/
total 16
-rw-r--r-- 1 root root 676 Oct 8 20:47 CentOS-Base.repo # 标准源
-rw-r--r-- 1 root root 230 Aug 27 10:31 epel.repo # 扩展源
2. vim编辑器
vim是vi的升级版,vi是早期开发时使用的,用起来非常蛋疼,而vim作为vi的升级版本,堪称promax,vim不但兼容了vi的所有指令,还包含了许多新的特性。
例如语法加亮,可视化操作不仅可以在终端运⾏,也可运行在x window、 mac os、 windows。
2.1 vim的基本概念
首先,我们使用 vim 【文件名】 的指令进行进入vim编辑器
vim有十几种模式,我们这里讲解最主要用到的5种。如下图所示
• 正常/普通/命令模式(Norma mode)
控制屏幕光标的移动,字符、字或⾏的删除,移动复制某区段及进⼊插入模式下,或者到 末行模式,这也是我们进入一进入vim编辑器就处于的模式。
• 插入模式(Insert mode)
只有在此模式下才可以编辑文本,进行文字输入,按「ESC」课返回命令模式
• 末行模式
⽂件保存或退出,也可以进⾏⽂件替换,找字符串,列出⾏号等操作。
在命令模式下,”shift + ;“ (即 “ : ” )即可进⼊该模式。
• 替换模式
命令模式下按“ shift + r” 即可进入,在该模式下,师傅的方式为替换光标处的文字
• 视图模式
用于选中特定区域的文本,并对限定区域的文本进行批量操作。
总结:命令模式是最重要的,他是各个模式之间互通的桥梁。
2.2 vim命令模式基础指令
命令模式主要是沟通各个模式的桥梁,我们主要需要掌握的是从该模式去往其他模式的指令,以及如何从其他模式回到命令模式。
2.3 vim插入模式基础指令
有三种方法从命令模式进入插入模式,这三种方法略有不同
• 按「i」切换进⼊插⼊模式「insertmode」,按“i”进⼊插⼊模式后是从光标当前位置开始输⼊⽂件;
• 按「a」进⼊插⼊模式后,是从⽬前光标所在位置的下⼀个位置开始输⼊⽂字;、
• 按「o」进⼊插⼊模式后,是插⼊新的⼀⾏,从⾏⾸开始输⼊⽂字。
移动鼠标:
注意,在插入模式下我们是无法通过鼠标点击来控制光标的移动的,所以需要键盘使用来控制光标移动
• vim可以直接⽤键盘上的光标来上下左右移动,但正规的vim是⽤⼩写英⽂字⺟「h」、「j」、「k」、「l」,分别控制光标左、下、上、右移⼀格
• 按「G」:移动到⽂章的最后
• 按「 $ 」:移动到光标所在⾏的“⾏尾”
• 按「^」:移动到光标所在⾏的“⾏⾸”
• 按「w」:光标跳到下个字的开头
• 按「e」:光标跳到下个字的字尾
• 按「b」:光标回到上个字的开头
• 按「#l」:光标移到该⾏的第#个位置,如:5l,56l
• 按[gg]:进⼊到⽂本开始
• 按[shift+g]:进⼊⽂本末端
• 按「ctrl」+「b」:屏幕往“后”移动⼀⻚
• 按「ctrl」+「f」:屏幕往“前”移动⼀⻚
• 按「ctrl」+「u」:屏幕往“后”移动半⻚
• 按「ctrl」+「d」:屏幕往“前”移动半⻚
删除文字
• 「x」:每按⼀次,删除光标所在位置的⼀个字符• 「#x」:例如,「6x」表⽰删除光标所在位置的“后⾯(包含⾃⼰在内)”6个字符
• 「X」:⼤写的X,每按⼀次,删除光标所在位置的“前⾯”⼀个字符
• 「#X」:例如,「20X」表⽰删除光标所在位置的“前⾯”20个字符
• 「dd」:删除光标所在⾏
• 「#dd」:从光标所在⾏开始删除#⾏
复制
• 「yw」:将光标所在之处到字尾的字符复制到缓冲区中。
• 「#yw」:复制#个字到缓冲区
• 「yy」:复制光标所在⾏到缓冲区
• 「#yy」:例如,「6yy」表⽰拷⻉从光标所在的该⾏“往下数”6⾏⽂字。
• 「p」:将缓冲区内的字符贴到光标所在位置。注意:所有与“y”有关的复制命令都必须
与 ” p” 配合才能完成复制与粘贴功能。
替换
•「r」:替换光标所在处的字符。
•「R」:替换光标所到之处的字符,直到按下「ESC」键为⽌。
•撤销上⼀次操作
•「u」:如果您误执⾏⼀个命令,可以⻢上按下「u」,回到上⼀个操作。按多次“u”可以执多次回复。
撤销上⼀次操作
• 「u」:如果您误执⾏⼀个命令,可以⻢上按下「u」,回到上⼀个操作。按多次“u”可以执⾏ 多次回复。
• 「ctrl + r」: 撤销的恢复
更改
• 「cw」:更改光标所在处的字到字尾处
• 「c#w」:例如,「c3w」表⽰更改3个字
跳⾄指定的⾏
• 「ctrl」+「g」列出光标所在⾏的⾏号。
• 「#G」:例如,「15G」,表⽰移动光标⾄⽂章的第15⾏⾸。
2.4 vim末行模式基础指令
列出⾏号
• 「set nu」:输⼊「set nu」后,会在⽂件中的每⼀⾏前⾯列出⾏号。
跳到⽂件中的某⼀⾏
• 「#」:「#」号表⽰⼀个数字,在冒号后输⼊⼀个数字,再按回⻋键就会跳到该⾏了,如输⼊数字 15,再回⻋,就会跳到⽂章的第15⾏。
查找字符
• 「/关键字」: 先按「/」键,再输⼊您想寻找的字符,如果第⼀次找的关键字不是您想要的,可以 ⼀直按「n」会往后寻找到您要的关键字为⽌
• 「?关键字」:先按「?」键,再输⼊您想寻找的字符,如果第⼀次找的关键字不是您想要的,可 以⼀直按「n」会往前寻找到您要的关键字为⽌。
保存⽂件
• 「w」: 在冒号输⼊字⺟「w」就可以将⽂件保存起来
离开vim
• 「q」:按「q」就是退出,如果⽆法离开vim,可以在「q」后跟⼀个「!」强制离开vim • 「wq」:⼀般建议离开时,搭配「w」⼀起使⽤,这样在退出的时候还可以保存⽂件
2.5 视图模式基础指令
批量化去注释
hjkl(选中编辑区域)-> shift + i(进入插入模式,因为此模式下才能编辑文本)-> // -> Esc
上述演示只是实例,我们需要明白的是:在视图模式下库批量选择区域,此时再进入插入模式即可进行我们需要的操作实现批量化编辑文本。
2-6 简单vim配置[了解]
常⽤配置选项,⽤来测试
• 设置语法⾼亮:syntax on
• 显⽰⾏号: set nu
• 设置缩进的空格数为4:set shiftwidth=4
插件:虽然插件可以让vim界面更好看,功能更全,但可能会出现一些报错,不建议初学者使用,所以这里不赘述。
3. 编译器gcc/g++
gcc:只能用来编译c语言 g++:课编译c语言和c++
31 背景知识
从一个.c文件到生成可执行程序一共有四步:
1. 预处理(进⾏宏替换/去注释/条件编译/头⽂件展开等)
2. 编译(⽣成汇编)
3. 汇编(⽣成机器可识别代码)
4. 连接(⽣成可执⾏⽂件或库⽂件)
下面我们主要讲解c语言的编译
3.2 gcc编译语法
格式 :gcc [选项] 要编译的⽂件 [选项] [⽬标⽂件]
3.2.1 预处理
• 选项“-E”,该选项的作⽤是让 gcc 在预处理结束后停⽌编译过程。
• 选项“-o”是指⽬标⽂件, “ .i ” ⽂件为已经过预处理的C原始程序
实例:
3.2.2 编译
在这个阶段中,gcc ⾸先要检查代码的规范性、是否有语法错误等,以确定代码的实际要做的⼯作, 在检查⽆误后,gcc 把代码翻译成汇编语⾔。
• 选项“-S”,该选项的作⽤是让 gcc 在编译结束后停⽌。
实例:
3.2.3 汇编
• 汇编阶段是把编译阶段⽣成的“.s”⽂件转成⽬标⽂件
实例:
3-2-4 连接
• 将 -o 文件与库文件进行连接,生成可执行程序
实例:
这个绿色的test就是可执行程序
3.3 动态连接和静态链接
再实际开发中,我们不可能将所有代码放在一个文件,而是采用多文件的形式存在,并且这多个文件之间并不是独立的,而是存在多种依赖关系
为了满⾜前⾯说的依赖关系,则需要将这些源⽂件产⽣的⽬标⽂件进⾏链接,从⽽形成⼀个可以执⾏的程序。这个链接的过程就是静态链接。
静态链接的缺点
1.浪费空间:因为每个可执⾏程序中对所有需要的⽬标⽂件都要有⼀份副本,所以如果多个程序对 同⼀个⽬标⽂件都有依赖,如多个程序中都调⽤了printf()函数,则这多个程序中都含有 printf.o,文件体量很大。
2. 更新⽐较困难:因为每当库函数的代码修改了,这个时候就需要重新进⾏编译链接形成可执⾏程 序。
静态链接的优点
1. 运行速度快:在可执⾏程序中已经具备了所有执⾏程序所需要的任何东西,在 执⾏的时候运⾏速度快
2. 不依赖库:静态链接完毕之后文件中以已经自己包含了相应的库,即使把库删了也不影响。
动态链接的出现解决了静态链接中提到问题
动态链接的基本思想是把程序按照模块拆分成各个相对 独⽴部分,在程序运⾏时才将它们链接在⼀起形成⼀个完整的程序,⽽不是像静态链接⼀样把所有程序模块都链接成⼀个单独的可执⾏⽂件。
3.4 静态库动态库
在3.3中我们涉及到⼀个重要
yum install glibc-static libstdc++-static -y
的概念:库
我们的C程序中,并没有定义“printf”的函数实现,且在预编译中包含的“stdio.h”中也只有该 函数的声明,⽽没有定义函数的实现,那么,是在哪⾥实“printf”函数的呢?
答案是:系统把这些函数实现都被做到名为 libc.so.6 的库⽂件中去了,在没有特别指定 时,gcc 会到系统默认的搜索路径“/usr/lib”下进⾏查找,也就是链接到 libc.so.6 库函数中去,这样 就能实现函数“printf”了,⽽这也就是链接的作⽤
• 静态库是指编译链接时,把库⽂件的代码全部加⼊到可执⾏⽂件中,因此⽣成的⽂件⽐较⼤,但在运 ⾏时也就不再需要库⽂件了。其后缀名⼀般为“.a”
• 动态库与之相反,在编译链接时并没有把库⽂件的代码加⼊到可执⾏⽂件中,⽽是在程序执⾏时由 运⾏时链接⽂件加载库,这样可以节省系统的开销。动态库⼀般后缀名为“.so”,如前⾯所述的 libc.so.6 就是动态库。gcc 在编译时默认使⽤动态库。完成了链接之后,gcc 就可以⽣成可执⾏⽂ 件,如下所⽰。 gcc hello.o –o hello
⼀般我们的云服务器,C/C++的静态库并没有安装,可以采⽤如下⽅法安装
# Centos
yum install glibc-static libstdc++-static -y
4. 自动化构建-make/makefile
4.1 背景
一个文件从.c文件到可执行程序一共有四步,尽管我们可以将其合成为一步,但是每个文件都需要我们编译就很繁琐,这时候makefile这个文件就帮我解决了这个问题,他可以批量化理文件。
一个工程的源文件数不胜数而又分布在若干目录下,而makefile可以让我们来定义一些来的规则,指定哪些文件先编译,哪些后编译等
当我们有成百上千个.c文件需要编译时,也能通过makefile制定相关规则来批量化自动处理
而完成上述的操作时,只需要写好makefile文件中的规则关系,再实现一个命令“ make ” 即可。
4.2 基本使用
例如我们有一个test.c文件如下所示需要编译
#include
int main()
{
printf("hello Makefile!
");
return 0;
}
在makefile中
myproc:myproc.c
gcc -o myproc myproc.c
.PHONY:clean
clean:
rm -f myproc
在makfile的文件里,我们需要明确:目标文件,以来文件,以及两者依赖关系和依赖方法
我们需要编译这个文件去写成一个名为test的可执行程序,那么test这个可执行程序就是我们的目标文件,因为这是我最终要生成的文件。
并且,我们是通过test.c的文件去生成的,那么test.c就是我们的依赖文件
那么依赖方法便是我们需要用怎样的指令去生成出对应的文件
这里便是 gcc -o myproc myproc.c
这样,在使用make指令之后,他会去找目标文件的依赖文件,知道找到存在的依赖文件,便开始执行对应的依赖方法。
值得注意地是,若有多个目标文件以及目标关系,makefile在make时会以压栈的方式从上到下入栈,直到找到了对应的目标文件,在依次出栈执行对应的依赖方法。
最后,项目工程是需要被清理的。因此我们还有些一个clean的目标文件,但是clean这种,没有被第⼀个⽬标⽂件直接或间接关联,那么它后⾯所定义的命令将不会被⾃动 执⾏。所以我们需要手动的去实现make clean。
并且向clean的这种目标文件,我们一般将其定义为一个伪⽬标,⽤ .PHONY 修饰,伪⽬标的特性 是,总是被执⾏的,那么何为总是被执行?
我们用stat来查看了我们的test可执行程序的具体属性,这里我们主要关注三个:
Modify: 内容变更,时间更新。
Change:属性变更,时间更新。
Access:常指的是⽂件最近⼀次被访问的时间。
并不是每次运行make,makefile文件都会根据对应关系去执行,而是会根据当前文件的.c文件(依赖文件)的内容变更时间和对应的.exe(目标文件)来判断是否需要执行,而如果在目标文件钱加上.PHONY,则会让make忽略依赖⽂件和⽬标⽂件的时间对⽐。
4.3 推导过程及注意事项
前面提到过makefile文件中的执行逻辑是压栈的方式,这里我们以下面的makefile文件内容为例,逐步详解一下。
myproc:myproc.o
gcc myproc.o -o myproc
myproc.o:myproc.s
gcc -c myproc.s -o myproc.o
myproc.s:myproc.i
gcc -S myproc.i -o myproc.s
myproc.i:myproc.c
gcc -E myproc.c -o myproc.i
.PHONY:clean
clean:
rm -f *.i *.s *.o myproc
1. make会在当前⽬录下找名字叫“Makefile”或“makefile”的⽂件。
2. 如果找到,它会找⽂件中的第⼀个⽬标⽂件(target),在上⾯的例⼦中,他会找到 myproc 这 个⽂件,并把这个⽂件作为最终的⽬标⽂件。
3. 如果 myproc ⽂件不存在,或是 myproc 所依赖的后⾯的 myproc.o ⽂件的⽂件修改时间要 ⽐ myproc 这个⽂件新(可以⽤ touch 测试),那么,他就会执⾏后⾯所定义的命令来⽣成 myproc 这个⽂件。
4. 如果 myproc 所依赖的 myproc.o ⽂件不存在,那么 make 会在当前⽂件中找⽬标为 myproc.o ⽂件的依赖性,如果找到则再根据那⼀个规则⽣成 myproc.o ⽂件。(这有点像⼀ 个堆栈的过程)
RM=rm -f # 引⼊命令
5. 当然,你的C⽂件和H⽂件是存在的啦,于是 make 会⽣成 myproc.o ⽂件,然后再⽤ myproc.o ⽂件声明 make 的终极任务,也就是执⾏⽂件 hello 了。
6. 这就是整个make的依赖性,make会⼀层⼜⼀层地去找⽂件的依赖关系,直到最终编译出第⼀个 ⽬标⽂件。
需要注意的是,在找寻的过程中,如果出现错误,⽐如最后被依赖的⽂件找不到,那么make就会直接退出,并 报错,⽽对于所定义的命令的错误,或是编译不成功,make根本不理。
make只管⽂件的依赖性,如果在我找了依赖关系之后,冒号后⾯的⽂件还是不在,那么对 不起,我就不⼯作啦。或如果第一给目标文件就找到了对应的依赖文件,并且依赖关系正确,则执行完这一条后就退出,后面的语句就不管了。
4.4 扩展语法
我们可以自定义变量名称,例如:
BIN=proc.exe # 定义变量
CC=gcc
不过在使用的过程中需要注意,自定义的变量使用是 $( 变量名 ) 的格式。
如果有100个.c文件需要我们去编译,那么我们不可能写100给makefile,这里我们只需要用一个变量名表示这所有的.c文件即可,这里有两种方法。
SRC=$(shell ls *.c) # 采⽤shell命令⾏⽅式,获取当前所有.c⽂件名
SRC=$(wildcard *.c) # 或者使⽤ wildcard 函数,获取当前所有.c⽂件名
我们也可以给任意的指令命名
RM=rm -f # 引⼊命令
总体便是
BIN=proc.exe # 定义变量
CC=gcc
#SRC=$(shell ls *.c) # 采⽤shell命令⾏⽅式,获取当前所有.c⽂件名
SRC=$(wildcard *.c) # 或者使⽤ wildcard 函数,获取当前所有.c⽂件名
OBJ=$(SRC:.c=.o) # 将SRC的所有同名.c 替换 成为.o 形成⽬标⽂件列表
$(BIN):$(OBJ)
@$(CC) -o $@ $^ # $@:代表⽬标⽂件名。 $^: 代表依赖⽂件列表
@echo "linking ... $^ to $@"
%.o:%.c # %.c 展开当前⽬录下所有的.c。 %.o: 同时展开同
名.o
@$(CC) -c $< # %<: 对展开的依赖.c⽂件,⼀个⼀个的交给gcc。
@echo "compling ... $< to $@" # @:不回显命令
.PHONY:clean
clean:
$(RM) $(OBJ) $(BIN)
5. 版本控制器Git
当我们在工作时候,常面临提交的方案要改来改去的情况,最后却有可能面临 “感觉不如第一版” 的状况,因此我们选择在每一次版本的改动进行保存,在对应的拷贝文件上进行改动。这种方式在生活中也很常见,例如游戏的版本迭代,我们在网上可以找到一个单机游戏的不同版本的安装包,而我们写项目代码也是一样。
但在此之前的⼯作都需要这些不同版本的报告,于是每次都是复制粘贴副本,产出的⽂件就越来越 多,⽂件多不是问题,问题是:随着版本数量的不断增多,你还记得这些版本各⾃都是修改了什么 吗?
同样的,我们写项目代码也存在这个问题。于是版本控制器应运而生。
5.1 版本控制器
为了能够更⽅便我们管理这些不同版本的⽂件,便有了版本控制器。所谓的版本控制器,就是能让你 了解到⼀个⽂件的历史,以及它的发展过程的系统。通俗的讲就是⼀个可以记录⼯程的每⼀次改动和 版本迭代的⼀个管理系统,同时也⽅便多⼈协同作业。
⽬前最主流的版本控制器就是 Git 。Git 可以控制电脑上所有格式的⽂件,例如 doc、excel、dwg、 dgn、rvt等等。对于我们开发⼈员来说,Git 最重要的就是可以帮助我们管理软件开发项⽬中的源代码⽂件!
5.2 Git的安装
只需要使用yum指令安装对应的安装包即可
yum install git
5.3 建立远端Git仓库
我们的项目工程保存在了本地,但是一旦设备出问题数据无法恢复便能会很头疼,于是我们国外有github,国内有gitee网站,我们可以在其网站上建立远程仓库,我们可以用将其设为公有这样大家之间可以互相查看资源,也可以设为私有,只允许自己查看。
在gitee网站上建立好了远程仓库之后,我们便可以将本地的项目代码上传到gitee远程仓库中。一代本地数据丢失了,我们还可以从远程仓库将数据拉取下来。字本地做完改动之后,再将数据上传到远程仓库。
并且在本地,还存在一个暂存区,这是因为我们在本地肯定会对项目代码进行频繁的改动, 为了避免存在避免频繁的上传,在本地修改好的代码都会先存放在暂存区,而后再确定无需再修改之后,统一的将暂存区的代码保存到本地的仓库,再将本地的仓库数据提交同步到远端的git仓库。
5.4 建立本地Git仓库
在建立好远端仓库之后,会有一个远端仓库的url
我们只需在linux中使用以下代码,便可建立本地的仓库
git clone [url]
这⾥的 url 就是刚刚建⽴好的项⽬的url,复制过来即可。
5.5 Git三板斧
在5.3中,我们大致描述了git的同步过程,总体可以分为三步,也成为git三板斧。
5.5.1 git add
这一步,便是将我们修改或者新建过的文件名加入暂存区。
git add [⽂件名]
5.5.2 git commit
这一步,是将暂存区的数据统一保存到git的本地仓库,“XXX” 表示日志内容,表明你这次的版本更新都做了什么。
git commit -m "XXX"
5.5.3 git push
这一步,便是将数据从本地仓库上传更新到远端仓库
git push
当然,首次使用 Git 时,你需要配置你的用户名和邮箱。这些信息将用于标识你在提交代码时的身份。配置用户名和邮箱的命令如下:
# 配置全局用户名
git config --global user.name "Your Name"
# 配置全局邮箱
git config --global user.email "your.email@example.com"
--global 选项表示这些配置将应用于你系统中的所有 Git 仓库。如果你只想为某个特定的仓库配置用户名和邮箱,去掉 --global 选项即可。
如此,便是git代码的三板斧,会后这些操作便已经足够我们进行项目的开发。
6. 调试器gdb/cgdb的使用
6.1 示例代码
// mycmd.c
#include
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
");
int n = Sum(start, end);
printf("running done, result is: [%d-%d]=%d
", start, end, n);
return 0;
}
程序的发布⽅式有两种, debug 模式和 release 模式, Linux gcc/g++ 出来的⼆进制程 序,默认是 release 模式。
要使⽤gdb调试代码,必须在源代码⽣成⼆进制程序的时候, 加上 -g 选项,如果没有添加,程序⽆法调试
gdb的使用非常难受,所以我们安装cgdb软件包,cgdb的使用相对方便一些,下述操作都是在cgdb上进行。
#cgdb的安装
sudo yum install -y cgdb
6.2 常见使用
开始:cgdb [文件名称]
退出:ctrl + d 或 quit 调试命令
6.3 cgdb实用指令
有了上述基础指令还不够,这里再介绍三种实用的指令帮助我们进行调试
6.3.1 watch
语法: watch [变量名]
watch指令可以帮助我们监视变量名的变化,在每一次执行语句后若变量名发生变化,那么便会将监视的变量旧值和新值都打印出来
当然其用处一般是:若我们不希望一个变量发生变化,便使用watch对其进行监视,若发生变化了watch便可以告诉我们。
6.3.2 set var
set var 通常用来修改变量的值。这对于调试过程中需要临时更改变量值的情况非常有用。
语法:set var [变量名] = [修改后的值]
当我们程序出现报错,我们想确定是不是某一特定变量导致的错误时,我们可以使用这条语句修改特定变量的值,观察程序运行结果。
例如以下程序
// mycmd.c
#include
int flag = 0; // 错误
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
");
int n = Sum(start, end);
printf("running done, result is: [%d-%d]=%d
", start, end, n);
return 0;
}
我们误将flag的值由1写成了0,则会得到以下结果。
我们使用cgdb调试若想判断是不是flag的错误可以使用语句修改其值
修改flag的值后,发现是其造成了值的错误
6.3.3 条件断点
条件断点是使程序运行到特定的情况下停止运行,这再调试中相当实用
语法:b [行号] if [条件]
在我们实例中,执行累加的函数要执行00次,我想跳过前98次,就i观察最后两次的变化就可以使用 b 9 if i==98 ,在使用r之后程序就还跑到i=98的时候停止,这时候我们就可以使用s逐步的观察程序。
7. 总结
如上就是我们在开发过程中所用到的开发工具,我们学习了yum的软件包安装,了解了vim编辑器的运用,掌握了makefiel自动化构建的运用,以及了解git三板斧和cgdb的调试器。
博客知识一种对知识点的总结和归纳,我们需要需要在日常中不断的使用,才能熟练的掌握这些开发用的使用及其技巧。