调试的学习这里以VS为例
1.调试的基本步骤
.发现程序错误
.以隔离,消除等方式对错误进行定位
.确定错误产生的原因
.提出纠正错误的解决办法
.对错误予以改正,重新测试
2.Debug和Release的介绍
.Debug通常称为调试版本,它包含调试信息,切不做任何优化,便于程序员调试程序
.Release称为发布版本,它往往是进行了各种优化,使得程序在代码大小和运算速度都是最优的,以便用户能很好使用。
调试代码需要Debug版本
3.windows的调试环境
.1调试环境的准备---Debug版本
注意版本的选择,这里以vs为例。
.2学会调试的快捷键
一般我们就使用这些键
F5开始调试 ctri+F5不调试
F9 设置与取消断点 F10 逐过程 F11逐语句
若F10不起作用 则Fn+F10,其他键也是如此,Fn是有辅助效果的。
举例子打印一到十的代码:
int main() { int i = 0; for (i = 0; i < 10; i++) { printf("%d", i); } return 0; }
按住F10后,逐过程分析,进入调试
继续F10,开始从第一条语句执行,每循环一次打印一个数,每执行一个循环,就打印一个数。
我们可以一步步观察执行语句时对应的变化。当全部打印完后:
箭头指向最后,完成main函数的全部语句。
但是F10是逐过程,他执行每一步只够就下一步,无法观察函数内部是怎样的,但是F11会进入函数内部,一句句的执行。
我们在看F11逐语句分析程序运行过程中函数的调用:
会进入函数内部,函数执行打印heh后,之后就退出函数。
对于F5适是和F9配合使用的:
F9 设置与取消断点 F5开始调试
对你需要设置断点的语句的那一行点击F9就可以设置断点在该一行。
一般在认为在调试过程中,认为代码的错误在中间或后面,并不是从头开始调试,只是针对认为错的那一部分去调试,我们可以利用F9设置断点在这些你认为有错误的语句,之后F5进行调试。
但是在未被设置断点之前的语句会执行。
比如我们这里认为从第二个循环有错误:
断点前的语句会被执行,从断点处开始,开始调试断点处的语句。
当然断点是针对语句逻辑的断点,比如在循环中,执行完这一条语句后又回到了之前断点处,并不是一定是下一个断点。
在这里还有一个技巧,再利用F5调试的时候,倘若面对的是一个庞大的循环结构,而我们认为错误是在循环第100词,或第一千次的时候,我们不可能一直F5调试到那么多次。
故我们可以在断点处添加条件,只有条件为真时,断点才生效,避免多次的按键。
在断点处右击鼠标,选择条件
如这里设置只有当i=5的时候,断点才生效:
我们发现打印了五次hehe,之后在断点处停止了,之后就可以继续调试了。
4.调试的时候查看程序当前的信息
1.查看临时变量
点击调试后,我们发现在调试处多很多选项,其中窗口处也有许多选项:
我们可以一了解一下这些技巧:
1.自动窗口
在调试开始后,慢慢的,可以识别变量并在调试过程中记录变量的变化。
识别到i,且在每一次调试过程中,记录i的变化,不用手动开,但是自动取消结果,后展示变量下一次结果,还是不够灵活。
2.局部变量窗口
与自动窗口类似,但限制了变量为局部变量。
3.监视窗口
是最常用的窗口,可以自己选择监视的对象。
选择一个监视窗口,输入所要监视的变量,或变量的地址,观察他们在调试过程中的变化。
监视窗口用起来是非常的灵活的,自我选择监视对象。
在监视窗口上时,若监视的是一类数据如数据,我们可以输入 变量,数字 ,数字代表你所要观察的几个数据。
4.内存窗口
当代码运行后,我们可以看到代码的内存布局是如何的。
比方说这里打开内存窗口,输入arr回车确定,在按F10进入下一步,
这里我们就可以观察数组里的每个数在内存中是如何保存的,
在内存中,本来放的是二进制数据,但是为了显示方便,显示的时候是16进制的。
四个二进制转化为一个16进制的
即使是16进制,当然我们也可以观察字符型的,但参考效果一般
5.反汇编窗口
在这里反汇编窗口与寄存器窗口也能看到内存信息。
我们在这里能看到c语言被翻译成的汇编代码
我们可以看到每条语句里的反汇编代码,F10一条条的执行。
在不同平台上,汇编代码不是相同的。
6.寄存器窗口
查看寄存器上存放的数据内存,
如果你了解各种寄存器的名字如:eax,esp,ebp等,则可以利用监视窗口观察他们中的存放的数据的内存
寄存器上的:
监视窗口看的到的一些:
7.调用堆栈窗口
数据结构中:栈 与 队列
栈里的数据先进后出 队列里的数据后进先出
调用堆栈,就是利用栈的特点观察函数之间的调用关系。
比如说在这里我们利用F11逐语句观察,每到函数调用,调用堆栈都会记录该函数,先被调用先记录,直到调用完开始一个个返回时。就类似栈一样,先调用的在下面,最后调用的在上面,这类似于进栈
在返回时,从头顶的函数先返回,先消失,到最后面最开始被调用的函数,类似于出栈。
从结构上我们就可以看到函数调用关系。
我们需要多多动手去调试,熟练的运用着调试!!