makefile与gdb的使用
✨前言✨
📘 博客主页:to Keep博客主页
🙆欢迎关注,👍点赞,📝留言评论
⏳首发时间:2024年10月11日
📨 博主码云地址:渣渣C
📕参考书籍:C语言程序与设计 和 数据结构(C语言版)
📢编程练习:牛客网+力扣网
Linux常用的两个工具
- 1 make与makefile
- 1.1 了解makefile
- 1.2 ACM时间
- 2 gdb调试工具的使用
- 2.1 断点操作
- 2.2 查看变量操作
- 2.3 范围查找bug操作
1 make与makefile
1.1 了解makefile
首先我们必须明白的就是make是一个指令,makefile就是一个文件!makefile文件中主要包含的内容如下所示:
mybin被称为目标文件,也就是要生成的文件,code.c就是依赖文件列表,一般就是指的我们源文件,可以是多个源文件,这里只是以一个为例子!gcc这条语句就被叫做依赖方法!前面必须是一个TAB键开头!这样我们就简单的写好了一个makefile(m大小写都可以,这里就统一使用了小写)!我们保存之后,直接使用make指令就可以对该目录下的code.c这个源文件进行编译了!
果然就生成了mybin的可执行文件了!删除的话,我们在makefile文件中增加一个clean目标文件,该目标文件不依赖于任何的文件!
我们如何执行这个指令呢?我们不能直接使用make,而是要使用make clean才可以执行该指令!为什么直接生成mybin不用呢?事实上,使用make命令时,Linux会从上到下去扫描makefile文件,默认就会执行第一个依赖方法,也就是说就会自动生成第一个目标文件并且默认就只形成一个!
1.2 ACM时间
我们如果使用make指令之后在进行make,我们可以发现,依赖方法就不在执行了
我们先来介绍一下文件的三个时间,Access指的是最近查看文件的时间,这个时间并不是每查看一次就会立马更新,而是又自己的更新原则的!Change时间指的就是文件属性的改变时间,Modify就是文件内容修改的时间,所以通常Modify时间的改变也会引起Change时间的改变!我们在来说说,使用make指令时,系统就会将我们生成的目标文件的modify时间与依赖文件的Modify时间进行对比,如果我们目标文件的Modify时间比依赖文件的Modify时间要更新,那么此时就不用在编译,所以就不会在执行该方法!有没有什么办法可以让我们避免这种比较呢?makefile中就提供了.PHONY
关键字(表示该目标是一个伪目标,可以总是被执行)来帮助我们!
当然了,对于make与makefile提供的这种比较当然是好的,有助于我们进行开发!.PHONY
关键字的用法一般如下所示,将我们的clean作为一个伪目标:
makefile还可以用对变量进行定义,然后替换!$@表示就是目标文件, $^表示就是依赖文件列表,cc表示自定义变量
2 gdb调试工具的使用
我们需要先安装gdb调试工具(以centos 7为例)!安装命令如下:
yum install -y gdb
我们就可以使用gdb命令进入调试状态了!我们先创建一个code.c的文件,内容如下所示:
我们在编写一个makefile自动编译文件!内容如下:
然后我们利用make命令就可以编译生成对应的代码,我们使用gdb+编译好目标代码就可以进入gdb的调试环境!但是我们编译所生成的代码一定要是debug版本的,debug版本是带有调试信息的,适合我们开发人员进行调试,这样进入gdb环境下才可以进行调试,因为release版本是不可以进行调试的,不带调试信息的,所以适合测试人员进行测试!那么在Linux环境下,默认的编译方式是生成release版本的,如何让它生成debug版本的呢?我们只需要在makefile文件中做以下改动就可以了!
因此我们也可以总结出,gcc编译默认生成的就是release版本,是默认动态链接的!
下面我们就来简单的介绍一下,gdb中常见的调试命令(在gdb中,如果不输入指令,会默认在上一条指令执行完毕之后,在次执行该指令):
quit ~~~~~~ //退出gdb调试环境
l+行号 ~~~~~~ //显示源文件(test.c)某行之后的代码
2.1 断点操作
b + 行号 ~~~~ //表示在第几行打断点了
info + b ~~~~ //查看有哪几个断点
我们可以发现,在Linux中,断点是进行了标号的,那么如何删除断点呢?在Linux中,断点删除的指令如下所示:
d + 断点序号
我们还可以让断点失能,就是不起作用!相当于我们VS中禁用断点的功能!
disable + 断点序号 ~~~~ //禁用该断点
enable + 断点序号 ~~~~ //启用该断点
2.2 查看变量操作
查看变量操作之前,我们需要先了解两个指令先,一个就是我们的逐过程,一个就是我们的逐语句!
n ~~~~ //逐过程
s ~~~~ //逐语句
我们可以在上述代码中的第十七行打上一个断点,然后我们开始运行程序,先使用n然后重新运行程序使用s,这样我们就可以发现使用n就可以直接跳到下一句了,而使用s就会进入到函数内部!我们如何查看一个变量与变量的地址呢?所要用到的指令如下所示:
p + 变量 ~~~~ //使用该指令就是临时查看一下变量或者变量地址,不会一直显示的
display + 变量 ~~~~ //使用该指令就是查看一下变量或者变量地址,会一直显示的,并且也会随着程序的运行而发生变化
info display ~~~~ //查看常显示的变量或地址列表
undisplay + 序号 ~~~~ //删除要常显示的变量与地址
2.3 范围查找bug操作
gdb本质就是为了帮助我们快速的找到程序所在的bug,然后我们在对bug进行修改!
c ~~~~ //从一个断点运行到下一个断点
finish ~~~~ //将一个函数(不包括main函数)运行完毕就停下来
until + 行号 ~~~~ //在一个范围内,运行到指定行,比如在Sum函数中,在这个函数范围内,我们利用until+行号跳过循环!
bt ~~~~ //用来查看当前是在哪一个栈帧上,也就是目前代码走到了那个函数里
set var 变量名 = 指定值 ~~~~ //通常用在程序中有分支语句,不用修改代码,就可以观察到,如果当前变量为另一种指定值的情况,程序运行的结果是怎么样的