前言
在编写代码时,是否有因为出现Bug而烦恼呢?记得网上有个段子讲到:一个程序员百分之二十的时间在写Bug,百分之八十的时间在修改Bug。由此可见,掌握一些实用的调试技巧,能提高我们查找Bug的效率,本文以Visual Studio 2019为例,详细讲解如何利用该编译器工具进行代码的调试。
一、什么是bug?
软件缺陷(Defect),常常又被叫做Bug。 [1]所谓软件缺陷,即为计算机软件或程序中存在的某种破坏正常运行能力的问题、错误,或者隐藏的功能缺陷。缺陷的存在会导致软件产品在某种程度上不能满足用户的需要。IEEE729-1983对缺陷有一个标准的定义:从产品内部看,缺陷是软件产品开发或维护过程中存在的错误、毛病等各种问题;从产品外部看,缺陷是系统所需要实现的某种功能的失效或违背。具体可参考百度百科:软件缺陷_百度百科 (baidu.com)
二、调试
2.1 调试是什么?
调试(英语:Debugging / Debug),又称除错,是发现和减少计算机程序或电子仪器设备中程序 错误的一个过程。
2.2 调试的基本步骤
- 发现程序错误的存在
这步通常是由以下三类人发现的:
- 程序员:在编写代码时,发现程序的错误
- 测试:程序编写完毕后,由测试人员发现
- 用户:程序上线后,被用户发现
- 以隔离、消除等方式对错误进行定位
- 确定错误产生的原因
- 提出纠正错误的解决方法
- 对程序错误予以改正,重新测试
2.3 Debug和Relese的介绍
在Visual Studio 编译器中,有两个版本,分别时Debug版本和Relese版本。
Debug:调试版本(一般用于程序员调试程序)
Relese:发布版本(一般用于测试人员测试)
当然,不同的版本是由区别的,区别体现在两方面:
运行后生产的程序大小不同:


- Debug 通常称为调试版本,它包含调试信息,并且不作任何优化,便于程序员调试程序。
- Release 称为发布版本,它往往是进行了各种优化,使得程序在代码大小和运行速度上都是最优 的,以便用户很好地使用。
进入调试后,效果不同:
- 调试时,Relese版本不能进行调试,直接给出结果
- Debug可以一步一步观察,可以调试
2.4 调试常用快捷键
F5 - 开始调试
- 开始调试,经常用来直接跳到下一个断点处。通常与F9配合实用
F9 - 创建断点和取消断点
- 什么是断点?对某条代码设置断点,意思就是该代码前的代码不需要调试,直接从该断点处开始调试,调试时应使用F5开始调试快捷键,会直接到断点处。
- 设置断点后,如果还想设置条件,如在循环中,想让i=某次,可以对鼠标右键点击条件,设置条件
F10 - 逐过程
- 通常用来处理一个过程,一个过程可以是一次函数调用,或者是一条语句。
- 不能进入函数内部,查看函数内部细节
F11 - 逐语句
- 就是每次都执行一条语句,但是这个快捷键可以使我们的执行逻辑进入函数内部(这是最 长用的)。
Ctrl + F5
- 开始执行不调试,如果你想让程序直接运行起来而不调试就可以直接使用。
注意:
- 有些电脑要配合fn一起使用,根据具体情况。
- F10和F11功能大致相同,不同点在于遇到函数时。
2.5 调试的时候查看程序当前信息
2.5.1 查看临时变量的值
这里介绍一个功能,用于查看调试过程中变量的值,可以仔细观察变量值的变化。

2.5.2 查看内存信息
如果想查看一个变量对应的内存信息,也是有对应方法的。

2.5.3 查看调用堆栈
什么是栈?其实是一种数据结构,特点是先进后出。调用堆栈功能一般用于有多个函数时,在C语言中,函数和局部变量是存放在栈区的,使用调用堆栈就能观察每个函数和局部变量的创建过程。
2.5.4 查看汇编信息
如何查看C语言翻译出来的汇编代码。
相同的,窗口功能下还有很多工具,老铁们可以自行测试。
2.6 如何写出易于调试的代码
优秀的代码:
- 代码运行正常
- bug很少
- 效率高
- 可读性高
- 可维护性高
- 注释清晰
- 文档齐全
常用的coding技巧:
- 使用assert
- 尽量使用const
- 养成良好的编码风格
- 添加必要的注释
- 避免编码的陷阱。
2.7 特殊代码
#include <stdio.h>
int main()
{
int i = 0;
int arr[] = {1,2,3,4,5,6,7,8,9,10};
for(i=0; i<=12; i++)
{
arr[i] = 0;
printf("hello bit\n");
}
return 0;
}
您认为结果是多少呢?大部分人看到该代码,第一反应是数组越界了,确实,该程序数组越界了,但我想告诉你,这个代码运行后是死循环,是不是很惊讶!
为什么呢?这是因为编译器分配空间的问题,我们知道局部变量或者函数是存放在栈区的,栈区是由低地址向高地址存储的,并且,在Visual Studio 2019中,分配给每个变量空间时,是间隔两个内存空间进行分配,因此这里的变量i和数组arr,其实是隔两个内存空间,因此当循环i++时,arr数组大小为10,当访问到 i == 12时,并且赋值为0,其实访问到了i的内存空间,将i的值改了,因此造成死循环。
当然,栈区中,每个变量之间间隔几个空间是由编译器决定的,可以得出:
Visual Studio中:2个
Linux下gcc中:1个
三、编译常见的错误
3.1 编译型错误
直接看错误提示信息(双击),解决问题。或者凭借经验就可以搞定。相对来说简单。
3.2 连接型错误
看错误提示信息,主要在代码中找到错误信息中的标识符,然后定位问题所在。一般是标识符名不 存在或者拼写错误。
3.3 运行时错误
借助调试,逐步定位问题。最难搞。
总结
写代码出现Bug是不可避免的,希望通过本篇文章,能帮助到大家更加轻松的解决Bug。