尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

Linux下的代码调试

Linux下的代码调试 调试1、什么样的程序才能调试2、初识gdb和cgdb3、cgdb调试指令3.1、断点3.2、逐过程与逐语句3.3、变量的观察3.4、跳出循环的方法3.5、其它指令4、三种调试技巧4.1、watch4.2、set var4.3、条件断点1、什么样的程序才能调试比如我们编写一个1~100求和的小程序编译出test.exe文件#includestdio.hintSum(ints,inte){intret0;for(intis;ie;i){reti;}returnret;}intmain(){intstart1;intend100;printf(I will begin.\n);intnSum(start,end);printf(running done, result is: [%d-%d]%d\n,start,end,n);return0;}使用gdb开始调试gdb [可执行文件名]但是我们会发现除了运行代码和退出调试我们无法对当前程序进行调试这是因为我们编译test.c的时候并没有生成调试信息。想要生成调试信息我们编译源文件的时候就需要带上-g选项这样得到的可执行文件就可以进行调试了因为带上了调试信息。意味着只有携带了调试信息的可执行文件才能进行调试。还记得我们在vs下编写的代码有Debug和Release两个版本的选项吗我们可以认为不带调试信息的可执行文件是Debug版本的软件而携带调试信息的可执行文件是Release版本的软件。这里我们也可以发现带上调试信息的可执行文件文件大小相比不带调试信息的文件变大了一些2、初识gdb和cgdb使用gdb进行代码调试gdb [可执行文件名]这时我们就可以展示代码、打断点、运行代码、单步调试、进入函数…输入quit可以退出调试。但是我们使用gdb的时候必须手动打印出调试信息才能观察调试过程。gdb的使用似乎不比我们之前使用vs 2022下的调试器方便。这时我们就可以使用另一个调试器cgdb。执行cgdb [可执行文件名]cgdb下调试控制台与代码展示是分离的这就比较像vs 2022很方便我们观察同时我们也能看到断点、指示运行到哪的小箭头等等。向上面这些调试器本质上就是帮助我们找到问题所在的辅助工具。3、cgdb调试指令gdb调试太麻烦了我们更常使用更方便的cgdb。l: list展示代码。r: run运行代码。3.1、断点断点的作用是进行区域化的代码执行帮助我们一步步缩小问题的范围以确定问题的位置。b行号: 给指定行打上断点。我们也可以指定文件打断点。info b: 查看断点信息。d [断点编号]: 删除指定行的断点。直接删除断点不是一个好习惯。我们建议保留调试痕迹这时可以对断点进行使能。disable [断点编号]: 禁用指定断点。enable [断点编号]: 启用指定断点。断点的编号设置也有点意思。我们打上三个断点我们删除断点2然后再在代码19行把断点加回来。我们就会发现代码19行的断点倒是加回来了然而断点的编号变为了4。原来在一个调试周期中断点的编号是线性递增的。上面示例中删除了断点2又加上了一个断点那么断点的编号就不是2了而是4。c: continue执行到下一个断点如果下面没有断点了就运行到结束。我们不仅可以指定行号打上断点还可以给函数打上断点b [函数名]: 对函数的函数体第一行打上断点。3.2、逐过程与逐语句之前使用vs的时候我们使用快捷键F10就可以逐过程执行代码即遇到函数调用直接当作语句执行使用F11就可以逐语句执行代码即遇到函数调用就进入函数。Linux下的逐过程执行指令是n(next)即遇到函数调用会直接跳过函数。要想进入函数内部我们可以执行指令s(step)。n, s指令的作用是小范围内进行一步一步调试进一步定位问题所在。3.3、变量的观察vs下有监视窗口我们可以在监视窗口中输入一些变量进而观察这些变量的变化情况。Linux下cgdb中也有观察变量的指令p(print)。还有p不仅可以可以打印变量也可以打印表达式然而p指令用得也不方便想查看变量值必须执行一次p指令即p指令只能临时查看变量。我们期望指定的变量能一直显示那就执行指令display [变量名]。如果我们想取消display显示的变量执行指令undisplay [编号]。3.4、跳出循环的方法假设我们排查问题的时候进入了一个循环。当我们确定这个循环没有问题的时候我们就想跳出循环。第一种方法就是在循环外打一个断点然后执行c指令第一种方法可能比较麻烦。我们可以使用第二种方法就是执行命令until [行号]。执行until语句就会执行到指定行位置上。比如我们until指定到第11行就可以跳出循环。对于until我们要注意三点until只能向下跳。如果强行向上跳默认执行当前函数直到结束。until不能跨函数。如果强行跨函数跳跃默认执行当前函数直到结束。until会自动跳过空格。我们还有第三种方法就是执行指令finish。finish作用到main函数以后调用的函数会直接执行到函数结束返回而finish作用到main函数则会报警告3.5、其它指令bt: 查看函数调用情况。info i: 查看与进程相关的信息。info locals: 查看当前作用域内的局部变量。4、三种调试技巧4.1、watchwatch指令可以监视指定的变量一旦变量有变化watch就会回显变化。比如我们监视retinfo b查看断点我们会发现多了一个watchpoint专门针对的是变量retret在Sum函数中自然是不断变化的。当ret变化时watch就会回显ret的变化那么watch的作用就很明显了watch可以用来对比变量变化的前后关系。其实watch还有一个作用那就是监视不能被改变的变量常用于监视不能随意改变的标志值以及指针。4.2、set var我们对上面的求和小程序做一点改动使得Sum既可以求1 ~ 100的和也可以求-1 ~ -100的和#includestdio.hintSum(ints,inte){intflag0;//int flag -1;//int flag 1;intret0;for(intis;ie;i){reti;}returnret*flag;}intmain(){intstart1;intend100;printf(I will begin.\n);intnSum(start,end);printf(running done, result is: [%d-%d]%d\n,start,end,n);return0;}运行上面代码发现结果为0不是我们的预期值。调试发现flag被设置成了0。当前我们验证问题的做法是退出调试修改代码重新调试以验证确实是flag出现了问题。可是这样做太麻烦了。这时我们就可以使用set var指令set var的作用是方便我们验证问题的原因应用于有标志值的地方(flag)if的条件上。比如某段代码中程序执行始终不进入其中一个if判断语句这时我们就可以使用set var修改if的判断条件。4.3、条件断点在一个循环周期中我们发现前面很多步操作都没问题就是某几步循环出现了一些小毛病。所以我们期望跳过正常的循环操作定位到不正常的循环操作。这时我们就可以使用条件断点。对于上面的循环假设前29次循环正常第30次循环出现了问题。那么我们就需要定位到第30次循环执行b 12 if i30。接着continue到下一个断点我们就会发现此时i确实变为了30我们就来到了第30次循环。条件断点的存在使得我们能够进行符合某种条件的Debug。当前12行断点不存在我们才执行上面的语句。那要是12行断点已经存在了呢执行condition [断点编号] i30。温馨小提示我们可能会遇到调试时乱点了什么东西之后调试命令行就什么也打不出来了。这时我们只需按i即可恢复。
返回列表