目录
引子: 什么是bug
BUG的英文释义是“虫子”,现在人们通常会将计算机上发生的一些问题,比如系统缺陷、程序漏洞、轻微毛病、问题、故障等统称为bug(漏洞),人类历史上第一个程序BUG就是与虫子有关。
1937年,有一天,计数人员在对一台计算机调试程序时出现故障,经过一阵子周折,发现有只飞蛾被烤糊在两个继电器触点的中间导致短路。于是把程序故障统称为“臭虫BUG”。
1. 调试及其重要性
所有的发生的事情都一定有迹可循,对于电脑程序来说也是如此,当问题出现时就一定有导致其发生的成因,迹象,迹象越多就越容易顺藤摸瓜,发现问题所在,着就是推理的途径,也是调试程序的方式。
在我们编写程序时,随着代码体量增大,功能的增多,就不免会出现各种各样的问题,如何发现解决这些问题,让程序正常运行。我们就需要依靠调试这一手段,接下来我们就来进行相关学习。
1.1 什么调试
调试(英语:Debugging / Debug),又称除错,是发现和减少计算机程序或电子仪器设备中程序错误的一个过程。
1.2 调试的基本过程
- 发现程序中错误的存在
- 以隔离,消除等方式对错误进行定位
- 确定错误产生的原因
- 提出纠正错误的解决方式
- 对程序出现的错误进行改正,重新测试。
注解步骤2:
隔离,消除的思想:从程序主干开始,一步一步将各个功能区释放,直至出现所发现的错误。或是分步将程序的功能区一次注释隔离,当程序不再报错时,当前备注的功能区即为错误所在。
1.3 Debug与Release
Debug通常被称为调试版本,它包含调试信息,并对程序不做任何优化,便于程序员调试程序。
Release称为发布版本,此版本的程序进行了各种优化,电脑在编译时不会为程序包含调试信息,使得程序在代码大小与运行速度上都是最优的,便于用户更好地使用。
当分别以不同模式编译程序时,会生成不同地目标文件。
2. windows调试环境调试介绍
2.1 调试环境地准备
环境选项中应选择debug选项,在此环境下代码才能正常调试。
2.2 调试中的快捷键
方式1:想要开始调试,可在菜单栏选中(调试 -> 开始调试)选项进行调试。
也可以通过快捷键进行调试,调试中最常用到的几个快捷键,如下:
F5
启动调试,经常用来直接跳到下一个断点处。
F9
创建断点与取消断点
断点:可以在程序任意位置设置断点,使得程序可以在想要停止执行的地方停止,然后再进行一步步调试
F10
逐过程地调试,一个过程可以是指一次函数地调用,或是一条语句。
F11
逐语句,即为每次执行一条语句,同时使用这个快捷键可以使得我们进入函数内部。
CRTL + F5
开始执行程序不调试。
2.3 调试时程序中相关信息地查看
2.3.1 查看临时变量的值
在调试开始后,观察各变量值得变化
Fn:辅助功能键
2.3.2 查看内存信息(快捷键:Alt + 6)
开始调试后,观察各个内存空间中内容得变化。
2.3.3 查看调用堆栈
函数调用堆栈:以栈的数据结构显示函数之间的调用关系
void test4()
{
printf("hello world\n");
}
void test3()
{
test4();
}
void test2()
{
test3();
}
void test1()
{
test2();
}
//示例,显示函数之间的调用关系
int main()
{
test1();
return 0;
}
2.3.4 查看汇编信息(Alt + 8)
查看代码的汇编形式
方式1:右击鼠标,选择(转到反汇编)
方式2:
2.3.5 查看寄存器信息(Alt + 5)
程序执行过程中,各个寄存器的变化。
3. 调试实例
3.1 实例1:
实现:计算1! + 2! + 3! + …+ n!的值
int main()
{
int i = 0;
int sum = 0;//保存最终结果
int n = 0;
int ret = 1;//保存n的阶乘
scanf("%d", &n);
for (i = 1; i <= n; i++)
{
int j = 0;
for (j = 1; j <= i; j++)
{
ret *= j;
}
sum += ret;
}
printf("%d\n", sum);
return 0;
}
当我们运行上述代码时,当输入为3时,结果应为1!+ 2!+ 3!= 1 + 1 × 2 + 3 × 2 × 1 = 1 + 2 + 6 = 9,可是我们却得到是15,调试确定问题原因。
ret 变量的值留有上一次计算的值,未清零。
3.2 实例2:
调试找出程序死循环的原因
int main()
{
int i = 0;
int arr[10] = {0};
for (i = 0; i < 12; i++)
{
arr[i] = 0;
printf("hello world\n");
}
return 0;
}
一次中方式定义数组与变量,在VS2019环境下,它们的内存空间位置如图,当数组越界访问arr[12]时,会更改掉 i 的值,使得变量永远无法增加至12。
补充:Release版本相较于Debug版本优化的验证
在上述的实例2中,在Debug版本下,此段程序会进行死循环并报错,但当我们以Release环境运行时,代码就会正常运行,当我们再通过内存观察时,数组 arr 的内存位置出现在了变量 i 之前。