1.什么是bug?
bug是飞蛾、臭虫的意思,世界上第一台计算机在工作时发现机器不工作了,当时的计算机科学家就在计算机中检查,结果发现一个飞蛾死在晶体管上了,清理后计算机又能继续工作了,工程师就把那只飞蛾贴在工作日志上,从此bug变成了运行异常的代名词。
2.调试是什么?有多重要?
我们说一名优秀的程序员就是一名出色的侦探。
每一次调试都是尝试破案的过程。
2.1调试是什么?
调试(英语:Debugging/Debug),又称除错,是发现和减少计算机程序或电子仪器设备中程序错误的一个过程。
2.2调试的基本步骤
1.发现程序错误的存在
2.以隔离、消除等方式对错误进行定位
3.确定错误产生的原因
4.提出纠正错误的解决办法
5.对程序错误予以改正,重新测试
2.3Debug和Release的介绍
Debug通常称为调试版本,它包含调试信息,并且不作任何优化,便于程序员调试程序
Release称为发布版本,它往往是进行了各种优化,使得程序在代码大小和运行速度上都是最优的,以便用户很好的使用。
编译器中可以选择版本:
下面我们来对比一下两个版本:
Debug版本:我们可以进行按F10键一步一步的调试,观察代码运行的过程
但是Realse版本中,按F10调试时,会直接跳过中间的运行过程,直接到运行的结果。
Realse版本是站在用户的角度,用户不需要调试代码,只需要最终的效果,所以一般Realse文件的大小比Debug文件更小,如果打开我们写代码的文件夹就会发现,当我们用不同版本编译后都会产生各自的文件夹,
3.Windows环境调试介绍
3.1调试环境的准备
在环境中选择debug选项,才能使代码正常调试。
3.2学会快捷键
想要学会调试,了解简单的快捷键必不可少。
F10:
逐过程,通常用来处理一个过程,一个过程可以是一次函数调用,或者是一条语句。
F11:
逐语句,就是每次都执行一条语句,但是这个快捷键可以使我们的执行逻辑进入函数内部(只是最常用的)。
这两种快捷键差不多,只不过,F10调试时会直接执行完函数,然后跳过,我们看不到函数的执行过程,而F11可以进入到函数内部,一步一步的执行完函数内部的每条语句。
F5:
启动调试,经常用来直接跳到下一个断点处
F9:
创建断点和取消断点
短点的重要作用,可以在程序的任意位置设置断点。
这样就可以使得程序在想要的位置随意停止执行,继而一步步执行下去。
F5和F9是配合使用的:
可以对下面代码先按F5调试一下:
#define _CRT_SECURE_NO_WARNINGS 1 #include<stdio.h> test() { printf("hehe\n"); printf("happy\n"); } int main() { int arr[10] = { 0,1,2,3,4,5,6,7,8,9 }; int i = 1; test(); return 0; }
我们可以发现,按F5调试会直接运行出结果,中间不停歇,那如果我们要想在代码的某一步停下来怎么办?
这时候就可以用F9键了,点击想要停下的那一行代码,然后按F9键,会发现这行代码前面出现一个圆形的红色标记,这就是断点的设置,
这时我们再按F5键就会发现,代码运行到断点标记的这一行就停住了,我们可以自行按F11键(或F10键)调试后面的代码。
通过监视窗口也可以看到,程序运行到第12行就停止了。
那如果说我们现在有不想再第12行停下来了,怎么办?
和设置断点的步骤相同,只需再次点击第12行,并且按F9键就会发现断点消失了。
所以F9键的作用不止是设置断点,还有取消断点。
注意:在设置两个断点时,按F5键永远只会在第一个断点停住,如果想在下一个断点处停住,只有取消前面的断点。
其实我们在设置断点之后还可以附加条件,比如下面一段代码:
#define _CRT_SECURE_NO_WARNINGS 1 #include<stdio.h> test() { printf("hehe\n"); printf("happy\n"); } int main() { int arr[10] = { 0 }; int i = 0; for (i = 0; i < 10; i++) { arr[i] = i; } for (i = 0; i < 10; i++) { printf("%d ", arr[i]); } test(); return 0; }
如果我不想再 i = 0的时候停下,我想在 i = 5的时候停下来,我们可以鼠标右击断点,找到条件,
然后添加条件为 i == 5,
接着再按F5键就会发现,程序运行到i = 5的时候停了下来。
Ctrl+F5:
开始执行不调试,如果你想让程序直接运行起来而不调试就可以直接使用。
什么意思呢?
就是如果我们已经设置了一堆断点,但是又不想在断点处停下来,这时直接按Ctrl+F5键,就可以直接执行完程序。(这和不设置断点时的F5键的作用一样)。
注意:如果说你的电脑上的F10、F11、F5等这些键按了之后不起作用,用Fn+F10、Fn+F11、Fn+F5就行。
3.3调试的时候查看程序当前信息
3.3.1查看临时变量的值
3.3.2查看内存信息
3.3.3查看调用堆栈
下面我们对这段代码,查看它调用堆栈的信息:
#define _CRT_SECURE_NO_WARNINGS 1 #include<stdio.h> void test3() { printf("haha\n"); } void test2() { test3(); } void test1() { test2(); } int main() { test1(); return 0;
当我们打开调用堆栈窗口时会发现,每次调用函数时,main函数上面就会出现其他函数,直到调用完,最顶上是test3函数,往下依次是test2、test1、main函数。
而当调用完所有函数后,开始返回,也是最顶上的函数先消失,最后只剩下main函数:
为什么会出现这样的情况呢?
这就需要讲一点数据结构的知识了。
数据结构中有栈和队列,数据在栈中存放时,只能从栈顶入,从栈顶出。而数据在队列时,只能从队尾进,队头出,就类似在食堂排队打饭一样,只能从队尾开始排,排到队头打到饭才能出。
3.3.4查看汇编信息
在调试开始之后,有两种方式转到汇编。
(1)第一种方式:右击鼠标,选择【转到反汇编】:
(2)第二种方式: