文章目录
将近一个星期没有更新
Linux
,SolidWorks
的文章,主要是因为上周是期末周,实在分心不过来,这段时间争取将之前欠的内容全部补上。也会补充我期末周复习的一些相关知识,我觉得那些东西还是很有用的
预备知识(9-2.30.00)
- 程序的发布⽅式有两种,
debug
模式和release
模式 debug
模式是程序员开发时候所用的模式,而release
模式下的程序会经过测试,上线等过程进行发布,手机上的APP和电脑上的软件都是release
版本- Linux环境下第一次使用
gdb
可能没有安装:sudo yum install -y gdb
Linux
下通过gcc/g++
编译好的代码是无法直接进行调试的, 因为Linux gcc/g++
出来的⼆进制程序,默认是release
模式
- 解决方式也很简单。程序要调试,那程序必须是
debug
模式,也就是编译时要加上-g
选项:gcc -g code.c -o code
,让最后形成的可执行程序,添加调试信息
- 通过命令可查看可执行程序的调试信息:
readelf -S code(可执行程序文件名)| grep -i debug
快速认识 gdb
1. 测试代码。这里如果用的是C89,这个for
循环的int i = 0;
放到括号外。当然也可以在编译处加上选项:-std=c99
#include <stdio.h>
int Sum(int s, int e)
{
int result = 0;
// int i = s;
// for(; i <=e; i++) C89的写法
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); //[start, end]
printf("running done, result is: [%d-%d]=%d\n", start, end, n);
return 0;
}
2. 进入调试:gdb 可执行程序名
。quit
:退出调试
l 1
:从第一行显示,按回车键可以往下翻继续查看源代码
b 19
:在代码的第19行打上断点,再输入r
,就让程序运行到第19行停下来,再输入c
,再让程序直接运行完成
gdb 的命令
1. 更换成 cgdb
先解决第一个gdb
难用的问题:gdb
它是纯命令行的方式进行调试,其调试信息和代码混在一起,非常的不方便
- 可以安装
cgdb
(默认环境没有安装该软件),可以呈现出对应的代码 - 输入命令:
sudo yum install -y cgdb
- 后面不作特殊说明,统一用
cgdb
作为命令的说明,这里如果用鼠标去滚动界面可能会卡死,我觉得这应该是cgdb
的bug
2. 打和去除断点
- 打断点:
b
后面可以跟源文件名:行号
,可以跟源文件名:函数名
,它是在函数的入口处打上断点,也可以直接跟上行号
- 查看所有断点的信息:
info b
,只要不退出cgdb
,断点编号是随着断点数量依次递增的,该断点是第几个打的,断点编号就是多少
- 删除断点:
d 断点编号
,无法根据断点所在行号来删除断点,只能根据该断点编号去删除断点
- 输入命令:
r
,如果存在断点则运行到断点处,没有断点则会运行完整个程序
3. 逐语句与逐过程
逐语句,输入命令:
s
,调试会进入到函数和循环中,以一句语句算作一步,一步一步地运行
逐过程,输入命令:
n
,调试并不会进入到函数和循环中,会直接跳过
打断点的本质就是让程序在特定位置停下来,对写的代码进行切块,按照断点的方式对程序进行局部性追踪
int n = Sum(start, end);
这条语句要做两个动作,第一个动作就是调这个Sum
函数,另一个动作就是将Sum
的返回值通过寄存器赋值给对应的用户
每一次函数调用的过程就是在形成栈帧的过程,在C语言调入栈中,每调一次函数就是把函数的栈中结构进行入栈。可以输入命令:
bt
,来查看入栈函数
如果要从函数中直接回到函数调用行(相当于执行完这个函数),输入命令:
finish
。想查看临时变量n的值,输入命令:p n
这里为啥n的值为
32767
呢?因为这只是Sum
函数调用完成(第一步),还没执行到下条语句(还没进行第二步的赋值),那此时的n
不就是个随机值
4. 使能(激活)断点
- 断点是可以被使能!意味断点可以打开使用,也可以关闭禁用(不是删除),这样断点的痕迹还在,下次调试的时候就很方便找到调试的历史痕迹
- 被使能:激活断点,输入命令:
enable
断点编号。没有被使能:禁用断点,输入命令:disable
断点编号,后面跟断点编号,不是断点所在的行号
调试思想
上面只是一些调试的基本命令,不涉及任何调试思想。调试的本质/核心工作: 首先你得知道这个代码有问题,所以调试它去找到问题所在(
gdb
有很多命令是找到问题所在), 查看代码的上下文,最后由你去解决问题
1. 找到问题(找到问题所在的区域)
- 断点的本质:就是把代码进行块级别划分,以块为单位进行快速定位区域,找到问题所在的区域
- 对代码进行切片分析。比如这块代码打上三个断点(20行有一个,25行,30行),打上断点后逐次分析每块代码片段
- 输入命令
r
运行到20行,如果没有啥问题,再输入命令c
跳到下一个断点处,运行第20~25行的这块代码
- 通过命令
finish
可以确认问题是否在函数内,就是将这个函数给跑完,没成功那问题就出现在这个函数
- 命令:
until 指定行号
,可以进行局部区域的快速执行。可以适用于跳出for
循环
2. 查看代码的上下文
- 这里假设我的n突然就等于0,我想通过调试找到问题所在,进入函数内部,要查看其变量的值
- 这里可以输入命令:
display 要常显示的值
,可以用来查看上下文的数据变化。不想常显示哪个值了输入命令:undisplay 对应值的编号
,不是变量的名称
p
也支持查看表达式的值。info locals
:可以查看函数或循环内的临时变量
补充调试技巧
1. watch
执⾏时监视⼀个表达式(如变量)的值。如果监视的表达式在程序运⾏期间的值发⽣变化,GDB 会暂停程序的执⾏,并通知使⽤者
删除它就跟删除断点一样,如果你有一些变量不应该修改,但是你怀疑它修改导致了问题,你就可以
watch
它,如果变化了就会通知你
2. set var
3. 条件断点
这样就可以直接跳到条件断点,输入命令:
c
也可以给已经存在的断点新增条件,输入命令:
condition 断点编号 条件
4. 分屏操作
cgdb
的分屏操作:可以通过Esc
键进入代码屏,i
键回到cgdb
屏,可以通过上下方向键进行翻阅(只有代码屏才能进行上下翻阅,cgdb
屏是翻阅历史命令)