开篇备忘录:观内心而本自具足,阅万物而虚怀若谷.
正文开始
1.什么是调试(debug)
当我们发现程序存在问题的时候,那麽下一步就是找到问题,并修复问题.这个找问题的过程称为调试,英文叫debug. 调试一个程序,首先是承认出现了问题, 然后通过各种手段去定位问题的位置,可能是逐过程的调试,也可能是隔离和屏蔽代码的方式,找到问题的位置,然后确定错误产生的原因,在修复代码,重新测试.
这里可以可以看到vs中有debug和release两个选项, debug通常称为调试版本, 开发人员可以更轻松地跟踪代码中的问题和错误. release称为发布版本.
2.调试快捷键
调试最常用的几个快捷键:
- F9:创建断点和取消断点
断点的作用是可以在程序的任意位置设置断点,打上断点就可以使得程序执行得到想要的位置暂停执行, 接下来我们就可以使用F10, F11这些快捷键, 观察代码的执行细节.
条件断点:满足这个条件,才触发断点
- F5:启动调试,经常用来直接跳到下一个断点处,一般是和F9配合使用.
- F10:逐过程,通常用来处理一个过程,一个过程可以是一次函数调用, 或者是一条语句.
- F11:逐语句,就是每次执行一条语句,但是这个快捷键可以使我们的执行逻辑进入函数内部. 在函数调用的地方, 想进入函数观察细节, 必须使用F11, 如果使用F10, 直接完成函数调用.
- CTRL+F5:开始执行不调试,如果想让整个程序直接运行起来而不用调试就可以直接使用.
3.监视的重要性
监视
- 我们需要先给程序打上一个断点
- 开始调试执行后,在菜单栏中 [调试] -> [窗口] ->[监视] , 打开任意一个监视窗口,输入想要观察的对象就行.
- 在监视窗口中观察
实例
在VS2022,X86,Debug的环境下,编译器不做任何优化的话,下面代码执行的结果是啥?
#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 world\n");
}
return 0;
}
以上代码会有两个问题:
- 数组访问越界
- 死循环
调试试试看?
当 i 的值为11时此时arr[11]已经被置为0,程序继续
当程序执行到 i 为12时, 神奇的一幕发生了, 此时arr[12] 的值为0 , 于此同时 i 的值也变成的0 , 这个程序的胆子也是真够大的啊 , 还好是虚拟内存
上面程序的内存分布如下:
- 栈内存的使用习惯是从高到低向内存地址使用的, 所以变量i的地址是较大的. arr数组的地址整体小于i的地址.
- 数组在内存中的存放是: 随着下标的增长,地址是由高到低变化的. for循环中,i的内容是从0,一直增加到12,而数组只有10个空间,因此会越界. 每次访问arr数组i号位置时,都会将该位置内容设置为0,当访问到arr[12]时,也会将该位置内容设置为0. 而该位置恰好为i的位置,即a[12]恰巧将i设置为0,因此造成死循环.
从这个理解我们能体会到调试的重要性, 只有调试才能观察到程序内部执行的细节, 就如同医生给病人做b超一样.
编程常见错误归类
-
编译型错误
一般都是语法错误,这类错误一般看错误信息就能找到一些蛛丝马迹, 双击错误信息也能初步跳转到代码错误的地方或者附近. 编译错误 , 随着对语言的不断熟悉掌握, 也会越来越少, 也容易解决. -
链接型错误
看错误信息,主要代码中找找到错误信息中的标识符,然后定位问题所在, 一般是因为
- 标识符名不存在
- 头文件没包含
- 拼写错误
- 引用的库不存在
- 运行时错误
运行时错误,是千变万化的,需要借助调试,逐步定位问题, 调试解决的是运行时的问题.
结尾
今天的分享就到这里, 在Visual Studio中,设置断点、单步调试、监视窗口、自定义调试信息、条件断点、异常处理、数据查看和多线程调试是一些常用的调试技巧,可以帮助提高代码调试的效率和准确性。通过这些技巧,开发人员可以更快速地定位和解决代码中的问题,提升开发效率和质量。希望这些技巧能够帮助您更好地进行代码调试和开发工作。