C语言入门(21)——使用DBG对C语言进行调试

程序中除了一目了然的Bug之外都需要一定的调试手段来分析到底错在哪。到目前为止我们的调试手段只有一种:根据程序执行时的出错现象假设错误原因,然后在代码中适当的位置插入printf,执行程序并分析打印结果,如果结果和预期的一样,就基本上证明了自己假设的错误原因,就可以动手修正Bug了,如果结果和预期的不一样,就根据结果做进一步的假设和分析。
我们介绍一种非常强大的调试工具gdb,可以完全操控程序的运行,并且随时可以查看程序中所有的内部状态,比如各变量的值、传给函数的参数、当前执行的语句位置等。调试的基本思想仍然“分析现象->假设错误原因->产生新的现象去验证假设”这样一个循环,根据现象如何假设错误原因,以及如何设计新的现象去验证假设,这都需要非常严密的分析和思考,如果因为手里有了强大的工具就滥用,而忽视了严谨的思维,往往会治标不治本地修正Bug,导致一个错误现象消失了但Bug仍然存在,甚至是把程序越改越错。

单步执行和跟踪函数调用

看下面的程序:

#include <stdio.h>int add_range(int low, int high)
{int i, sum = 0;for (i = low; i <= high; i++)sum = sum + i;return sum;
}int main(valoid)
{int result[100];result[0] = add_range(1, 10);result[1] = add_range(1, 100);printf("result[0]=%d\nresult[1]=%d\n", result[0], result[1]);return 0;
}

add_range函数从low加到high,在main函数中首先从1加到10,把结果保存下来,然后从1加到100,再把结果保存下来,最后打印出的两个结果是:

结果显然不正确,在小学我们就学了高斯小时候的故事,从1加到100应该是5050。下面通过gbd把错误找出来。

在编译时要加上-g选项,生成的目标文件才能用gdb进行调试:

(gdb) -g选项的作用是在目标文件中加入源代码的信息,比如目标文件中第几条机器指令对应源代码的第几行,但并不是把整个源文件嵌入到目标文件中,所以在调试时目标文件时必须保证gdb也能找到源文件。gdb提供一个类似shell的命令行环境,上面的(gdb)就是提示符,在这个提示符下输入help可以查看命令的类别:

可以进一步查看某一类别中有哪些命令,例如查看files类别下有哪些命令可以用:

现在试试用list命令从第一行开始列出源代码:

一次只列10行,如果要从11行开始继续列源代码可以输入

(gdb) list

也可以什么都不输直接敲回车,gdb提供了一个很方便的功能,在提示符下直接敲回车表示用适当的参数重复上一条命令。

gdb的很多常用命令有简写形式,例如list命令可以写成l,要列一个函数的源代码也可以用函数名做参数:

gcc的-g选项并不是把源代码嵌入到目标文件中的,在调试目标文件时也需要源文件。我们继续调试。首先用start命令开始执行程序:

这表示停在main函数中变量定义之后的第一条语句处等待我们发命令,gdb列出这条语句表示它还没执行,并且马上要执行。我们可以用next命令(简写为n)控制这些语句一条一条地执行:

用n命令依次执行两行赋值语句和一行打印语句,在执行打印语句时结果立刻打出来了,然后停在return语句之前等待我们发命令。虽然我们完全控制了程序的执行,但仍然看不出哪里错了,因为错误不在main函数而在add_range函数,现在用start命令重新来过,这次用step命令(简写为s)进入函数中去执行:

这次停在了函数中变量定义之后的第一条语句处。在函数中有几种查看状态的办法,backtrace命令(简写为bt)可以查看函数调用的栈帧:

可见当前的add_range函数是被main函数调用的,main传进来的参数是low=1,high=10。main函数的栈帧编号为1,add_range的栈帧编号为0。现在可以用info命令(简写为i)查看add_range局部变量的值:

用s或n往下走几步,然后用print命令(简写为p)打出变量sum的值:

根据上面两步的结果我们可以看到,变量sum没有做初始化,所以直接导致后面的运算结果错误。

这时候我们已经找到错误原因,可以退出gdb修改源代码了。

代码修改如下:

#include <stdio.h>int add_range(int low, int high)
{inti, sum = 0;for(i = low; i <= high; i++)sum= sum + i;returnsum;
}int main(void)
{intresult[100];result[0]= add_range(1, 10);result[1]= add_range(1, 100);printf("result[0]=%d\nresult[1]=%d\n",result[0], result[1]);return0;
}

修改完毕重新编译并运行:

发现结果正确了。

下面是常用的gdb指令:

backtrace(或bt) 查看各级函数调用及参数

finish 执行到当前函数返回,然后停下来等待命令

frame(或f) 帧编号 选择栈帧

info(或i) locals 查看当前栈帧局部变量的值

list(或l) 列出源代码,接着上次的位置往下列,每次列10行

list 行号 列出从第几行开始的源代码

list 函数名 列出某个函数的源代码

next(或n) 执行下一行语句

print(或p) 打印表达式的值,通过表达式可以修改变量的值或者调用函数

set var 修改变量的值

start 开始执行程序,停在main函数第一行语句前面等待命令

step(或s) 执行下一行语句,如果有函数调用则进入到函数中

C语言入门(21)——使用DBG对C语言进行调试相关推荐

  1. c语言入门自学ppt文库,《C语言入门基础》PPT课件.ppt

    第3章C语言入门基础 在正式学习C语言之前首先要掌握C语言的基本知识 如数制 对象的命名即标识符 以及C语言中的数据类型等 通过本章的学习为以后几章打下基础 3 1标识符 在C语言中 程序的编写是运用 ...

  2. c语言入门自学免费app,C语言入门学习最新版下载-C语言入门学习app手机版v1.0.2 安卓版-腾飞网...

    C语言入门学习app手机版是一款c语言编程自学软件,零基础也可以学习,里面有海量教学视频,针对c语言不同程度的讲解都囊括其中.随时随地学习编程都可以,不用担心自己没有基础.还支持在手机上敲代码编程哦. ...

  3. c语言入门经典18个程序,C语言入门经典

    面向C语言初学者,详细且全面地讲解了C语言的各种知识,从基础知识到高级应用,由浅入深,循序渐进地引领读者掌握C语言中的各种编程技术,体会C语言的灵活与强大.同时,<C语言入门经典>着眼于应 ...

  4. lua语言入门学习(二)lua语言的特点及注意事项

    lua语言入门学习 lua语言的特点及注意事项 文章目录 lua语言入门学习 lua语言的学习地址 一.lua语言特点 1.注释 2.全局变量和局部变量 3.lua数据类型 4.字符串类型 5.多变量 ...

  5. C语言二进制标识符,C语言入门基础大全,自学C语言必备知识!

    C语言作为一门非常适合编程入门的语言,打好基础的重要性不言而喻.所以特此奉上这一篇干货,希望小伙伴们能从中受益. 一.C语言程序的结构认识 用一个简单的c程序例子,介绍c语言的基本构成.格式.以及良好 ...

  6. R语言入门教程知识 第一章 R语言

         R语言 R是用于统计分析.绘图的语言和操作环境.R是属于GNU系统的一个自由.免费.源代码开放的软件,它是一个用于统计计算和统计制图的优秀工具. R语言特点 R作为一种统计分析软件,是集统计 ...

  7. c语言入门第6,c语言入门经典 第5版_c语言入门经典_c语言入门自学(6)

    1.8.5 函数体 main()函数的一般结构如图l-2 所示: 函数体是在函数名称后面位于起始及结束两个大括号之间的代码块.它包含了定义函数功能的所有语句.这个例子的main()函数体非常简单,只有 ...

  8. c语言入门程序下载,简单实用——C语言入门程序练习

    #include #include struct structstudent//创建结构体,表示学生信息 { int No;//学号 char Name[20];//姓名 int Age;//年龄 } ...

  9. 《c语言入门题目4》用c语言计算圆环的面积

    前言:(内容仅供分享和参考) 输入圆环内半径和圆环外半径即可获得圆环面积,是不是很高级(雾) bigR和smallR实际上都可以用r和R表示,没必要输的那么标准,但说明还是要说明清楚的. ====== ...

  10. 大一C语言入门到底怎么学

    大一C语言入门到底怎么学? 大一C语言入门按照下面路线来,以及把下面的100道C语言编程案例学会就入门啦- 入门篇 1.什么是计算机语言 2.C语言的程序的结构 3.运行C语言的步骤与方法 4.了解简 ...

最新文章

  1. python elseif用法_python学习笔记(一)
  2. Android在屏幕任意位置显示对话框
  3. web第五章 json
  4. 前端学习(1761):前端调试值之如何对站点下的资源进行全部搜索
  5. Android 8.0 学习(12)---init.rc语法及解析过程总结
  6. Node.js ES6 模块化的基本语法-按需导出与按需导入
  7. note 2 运算符和表达式
  8. [笔记分享] [Camera] msm8926 camera hal 流程小结
  9. 如何更换ppt模板内容不变_怎么修改固定的ppt模板中的字和图片
  10. Rsoft光波导软件基于七芯光纤波导耦合器模拟
  11. bootstrap-datepicker属性和方法
  12. 成功项目经理的能力提升
  13. Ubuntu 18.04 安装Wine 微信
  14. mysql快速复制数据库中所有表及数据至另一个库中
  15. JAVA图形面积与周长(抽象类)
  16. java写wss,JAVA模拟WebSocket客户端,支持wss ssl证书
  17. 仪器仪表的介绍及发展
  18. PAT乙级 1048. 数字加密(20)
  19. 配置基于区域策略的防火墙
  20. jquery日期控件jedate的学习

热门文章

  1. 三菱PLC学习SMOV指令
  2. 那些可多人协作编辑的在线文档工具
  3. 手机与软件兼容测试软件,如何使用Total Control手机软件兼容性测试?
  4. 王自如与老罗的辩论赛谁赢了?!
  5. 射频流盘与射频孪生——流盘技术应用(1)
  6. Linux上wget: 无法解析主机地址
  7. IntelliJ IDEA V2022.1版本亮点——改进框架与技术
  8. oracle实体视图日志,Oracle案例02——ORA-12034: SCOTT.USER_TABLE 上的实体化视图日志比上次刷新后的内容新...
  9. hexo+yilia主题添加评论
  10. 我写了个随机点名系统,非常好用~ 我给它取名叫做——随机点名系统