那要使用调式器调式,首先我们得有代码,有可执行程序。
所以,我先来写一个代码,写一下Makefile
然后我们来编译运行一下:
我们发现报错了
说的是“for”循环初始声明仅在C99模式中允许,即循环变量不能在for循环里面定义
这是因为我们得gcc的版本可能比较低,不支持C99
那怎么让它支持呢?
也很简单,在Makefile里面加一点东西
-std=c99
然后
就可以正常编译运行了
然后如何调式呢?
我们说了Linux中的调式器是gdb,那如何使用gdb调式
如果你的机器上没有gdb可以先安装一下:sudo yum install -y gdb
然后调式的话,第一步直接gdb+可执行文件名
然后我们输入相应的指令去调式的话,会发现调不成,有一个报错说的是找不到调试符号
其实就是生成的可执行程序中没有调式信息,怎么回事?又该怎么解决呢?
两者有什么区别呢?
Debug 通常称为调试版本,它包含调试信息,并且不作任何优化,便于程序员调试程序。
Release 称为发布版本,不包含调式信息,它往往是进行了各种优化,使得程序在代码大小和运行速度上都是最优的,以便用户很好地使用。
所以我们说调试就是在Debug版本的环境中,找代码中潜伏的问题的一个过程。
"Debug"和"Release"是软件开发过程中常见的两种构建(Build)配置。
Debug(调试)配置:
Debug 配置旨在方便开发人员在代码中进行调试和排查错误。
在 Debug 模式下,编译器会生成带有调试符号信息的可执行文件,这些符号信息包含了变量名、函数名和源代码行号等,以便在调试过程中能够准确地追踪错误。
Debug 配置通常会禁用一些优化,以便在调试过程中能够更好地观察程序的行为。
此配置的构建速度较慢,生成的可执行文件较大。
Release(发布)配置:
Release 配置旨在生成用于最终发布的、优化后的代码。
在 Release 模式下,编译器会对代码进行优化,以提高程序的执行效率和性能。
由于优化的存在,生成的可执行文件可能没有调试符号信息,并且可能会合并和删除一些不必要的代码。
Release 配置通常会启用各种优化策略,例如内联函数、循环展开和减少函数调用开销等,以提高代码的执行速度和资源利用率。
此配置的构建速度较快,生成的可执行文件较小。
在实际开发中,通常会使用 Debug 配置进行代码的开发、调试和测试,以便于快速定位和修复问题。而在准备发布软件时,会切换到 Release 配置,以生成性能更高、体积更小的最终可执行文件。
那在Linux上gcc/g++编译生成的可执行程序其实默认是release版本的,不包含调式信息,所以我们无法调式!
那如何让它以debug版本生成呢?
那为了以示区分,我把release版本的重命名一下
然后我们生成debug版本的,也重命名一下
那我们用gdb调式debug版本的话就不会出现刚才的报错信息了:
那具体调式要怎么做呢?
接下来我们就来学习一下,gdb中常用的调式操作所涉及的命令
那调式的时候,首先我们得能看到代码啊
打开调式是这样的,那我们想看看代码怎么做?
l(list)+行数
:就可以从指定行开始显示代码,一次默认显示10行
然后后面我们只输l
或者直接按回车键(因为gdb会记录你最近一次敲的命令)就可以继续往下显示
如果第一次只输l
的话,随机从某一行开始显示
那我们调式一般要设断点:
那如何设断点呢?
b(break point)+ 行号/函数名
:就可以把指定行或指定函数(打在函数内第一条语句处)设置为断点
如果是多文件的话,我们还可以指定文件去给对应的函数或指定行打断点
b 文件名:行号/函数名
(其实查看那里也可以这样来指定)
那设置好我们要查看断点,怎么查看呢?
这可不跟vs上一样,直接有一个红点标记
info b
:查看断点
这里的num是断点的编号,what就是断点的位置,在哪一个文件哪一行。
那有了断点,我们在开始调式的话,当然就会在断点处停下了
那如何删除一个断点呢?
对于断点呢还有一个比较冷门的操作,禁用和启用断点:
那在gdb上如何进行对应的操作呢?
大家看这个:
我们还是把16行设置成断点,然后我们查看的时候,第4列的信息enb(enable breakpoints)
如果是y,就表明当前断点是启用状态。
那如果不想删除它,把它设置成禁用,该怎么做呢?
disable breakpoints 断点编号
:禁用断点
然后enb
就变成了n
,就说明被禁用了
此时如果我们开始调式,它是不会起作用的:
那如果想启用呢?
enable breakpoints 断点编号
:启用断点
我们平时用vs调式的时候,常用的其实就是逐语句和逐过程:
逐过程其实就是一句一句往下执行,遇到函数调用也直接一次就走完了;而逐语句与逐过程的区别就是碰到函数的话会进入到函数体内。
那在gdb中与之对应的操作是什么呢?
首先逐过程:
那逐语句呢?
vs上我们调用一些函数的时候可以通过函数调用堆栈查看它们的调用关系:
那在gdb上如何查看?
那我们调式不是光一步步执行,重要的是在调式的过程中观察某些变量的值的变化是否和我们预想的一样,从而找出问题。
vs上可以通过监视窗口查看:
那gdb呢?
但是,这样好像有点挫啊,我们敲一次,它显示一次,不敲,下一条语句就不显示了。
那怎么让它一直显示,使得在程序执行的过程中我们可以观察变量的变化呢?
那现在是常显示,如果执行到某一步我不想让它显示了,怎么取消呢?
现在我们的这个函数的循环还没执行完:
才执行到i等于8,那现在如果我们单步执行的话他肯定还是一直在这循环,那我想直接让它跳转到循环结束,后面的第10行位置,能做到吗?
再来看一个:
我现在又进入到了这个函数里面
那我现在想让这个函数直接执行完,然后停下了
那就是finish
:执行到当前函数返回,然后停下来等待命令
c(continue)
:从当前位置执行到下一个断点停下来,后面没有断点则直接到程序结束
set var 变量名=值:修改变量的值
quit:退出gdb