你真的知道怎么使用vs吗?把把手教你实用调试小技巧

1.什么是bug?

谈到bug,我们知道bug的中文意思是虫子,飞蛾的意思。至于为什么bug一词会用到计算机领域的话得追溯到第一台计算机的诞生。
在这里插入图片描述
上面个你看到的就是世界上第一个bug的诞生。它的来源也是非常的有意思,当时世界上的第一台计算机出了故障不能正常的工作,于是工作人员就进入计算机内部检查(当时的计算机非常的大,达到人可以进去),这个时候发现计算机的一个晶体管内有个飞蛾死在了里面于是把飞蛾清理干净,换了零件之后,计算机就可以正常的工作了。于是科学家们就把此次事件记录了下来,一直延伸到现在,我们就把计算机成程序出问题说成是bug。

2.调试是什么?有多重要?

调试(英语:Debugging / Debug),又称除错,是发现和减少计算机程序或电子仪器设备中程序
错误的一个过程。

简单点说调试就是一个发现错误,并且精准的找到错误地点,找到合理的解决方案的一个纠错过程。

在程序员界里有这样一句话:一个优秀的程序员同时也是一个优秀的侦探。

  • 调试的基本步骤:
    1.发现程序错误的存在
    2.以隔离、消除等方式对错误进行定位
    3.确定错误产生的原因
    4.提出纠正错误的解决办法
    5.对程序错误予以改正,重新测试

3.debug和release的介绍。

  • Debug 通常称为调试版本,它包含调试信息,并且不作任何优化,便于程序员调试程序。
  • Release 称为发布版本,它往往是进行了各种优化,使得程序在代码大小和运行速度上都是最优 的,以便用户很好地使用。

当然两个版本还是有一些的不同之处的,就比如生成的可执行文件的大小是不一样的(.exe文件后缀名的文件);
在这里插入图片描述
在这里插入图片描述
我们先看Debug版本的:
在这里插入图片描述
再看Release版本的:
在这里插入图片描述

  • 这样一对比就可以看出了Release版本的可执行文件的大小是比Debug版本的小的,这是因为Release版本是对代码做了一些优化的,而我们的Debug版本是没有做优化的,所以在Release版本下的文件所占内存大小是更小的。

  • 那问题来了,既然有两个版本我们应该选择哪个版本呢?
    首先我们知道这两个版本的区别就是一个做了优化一个没有做优化。
    那既然我们要检查我们编写的代码哪里出问题了,是不是应该我们写的什么代码就调试什么代码,也就是说没有做任何的优化效果,这样的话及时是一点小错误我们也可以即使的发现并作出及时的改进。所以我们调试首选的就是Debug版本的。

  • 相反的,如果我们调试用的是Release版本的话,我们知道Release版本是对我们写的代码进行了优化作用的,如果我们用这个版本进行调试的话,有些错误的代码时被优化过的,那就说明一些较小的错误是不能被发现的,那么日积月累把这些小错误累计起来就会出大错误的。这么讲的话那Release版本到底在什么时候用到呢。我们要知道一点的时我们编写出来的文件终归是要给客户使用的,既然时给别人用的我们就要保证我们编写的程序不能出现错误,这个时候Release版本就有用出来,当我们调试的时候一些小的错误没有及时的发现就直接给用户使用,这个时候我么Release版本就会帮我们优化代码弥补那些小错误,这个时候客户就能正常的时候了。

4.windows环境调试介绍。

4.1常见调试快捷键

使用一些常用调试快捷键: 快捷键作用
F5 启动调试,经常用来直接跳到下一个断点处。
F9 创建断点和取消断点断点的重要作用,可以在程序的任意位置设置断点。这样就可以使得程序在想要的位置随意停止执行,继而一步步执行下去。
F10 逐过程,通常用来处理一个过程,一个过程可以是一次函数调用,或者是一条语句。
F11 逐语句,就是每次都执行一条语句,但是这个快捷键可以使我们的执行逻辑进入函数内部(这是最长用的)。
CTRL+F5 开始执行不调试,如果你想让程序直接运行起来而不调试就可以直接使用。
  1. CTRL+F5 直接执行
    我们代码后,想要直接看到我们编写的结果,就用这个组合键,就能在终端看到我们的编写结果了。这个是可以跳过断点的。
  2. F10逐步调试
    万一我们代码编写的时候出现了错误,我们也很难看出哪里出错了,这个时候就需要对我们的代码逐行的进行检验,这个时候我们就可以按F10
  3. F5 时执行键
    这个一般和F9断点搭配的使用,当我们设置好了断点之后,只需要按F5便会跳到断点处。
  4. F9 设计断点
    但我们编写的代码又几百行甚至更多的时候,而我们又知道他在那个部分出错了,如果我们还按F10逐行的进行检验的话就会浪费大量的时间和精力,这个时候我们可以设计断点。设计断点的方法有两种:1.选中一行按F9 。2.用鼠标左键点击改行最左边。当我们设置好了断点之后再按F5就可以直接跳到我们的断点处了。
    在这里插入图片描述

4.2 调试的时候查看程序当前信息

一般我们使用到的有:
在这里插入图片描述
注意这些都是在进行调试的时候才能使用的

扫描二维码关注公众号,回复: 15184559 查看本文章

4.2.1监视:

在这里插入图片描述
这个监视窗口我们可以自主输入想要看到结果,在按F10的过程最左边有一个箭头,这个箭头就是我们执行到哪一行的标志。
同时除了手动的,还用自动的。
在这里插入图片描述
自动窗口会根据你调试到哪里自动生成可监视的变量,但是他的局限性就是不能一直监视,一点过来变量的作用域就不能在监视了。

4.2.2内存

监视内存的方法和上面是一样的:
在这里插入图片描述

它可以显示处变量子内存的分布。

4.2.3调用堆栈

在这里插入图片描述

4.2.4反汇编

调用堆栈的方法有两种:1.鼠标右键点击转到反汇编。2.窗口打开
在这里插入图片描述
在这里插入图片描述

4.2.5寄存器

在这里插入图片描述

5.一些调试的实例。

实例一:

#include <stdio.h>
int main()
{
    int i = 0;
    int arr[10] = {0};
    for(i=0; i<=12; i++)
   {
        arr[i] = 0;
        printf("hehe\n");
   }
    return 0;
}

按我们的分析,这是一个数组访问越界问题。
我们先看Debug版本的:
在这里插入图片描述
这里发现程序进入死循环了(这里提示以下要改成x86状态下才能看到死循环的效果,如果时x64的话就会直接报错)这是为什么呢?
这个时候我我们就要明白有关内存问题了:
我们的内存分为栈区,堆区,静态区(后面都会详细的讲解),而我们主函数调用时在栈区的。
栈区的特点是:1.先使用高地址的空间,在使用低地址的处的空间。2.先进的后出,后进的先出。
我们看一下他们的汇编:
在这里插入图片描述
这里我们可以看到i的内存和arr[12]的内存地址重合了,也就说明当我们遍历到arr[12]并把arr[12]初始化为0的时候使用过地址改变arr[12]的,恰好我们i的地址也是arr[12]的地址,所以i就别改成了0,所以一旦i遍历到12的时候就有被改成了0,所以i又再次遍历,一直这样重复所以就会死循环。

那我们再看一下Release版本的:
在这里插入图片描述
会发现它就整整齐齐的打印了13个hehe,这就是Release版本的优化作用。

6.如何写出好(易于调试)的代码。

优秀的代码:

  1. 代码运行正常
  2. bug很少
  3. 效率高
  4. 可读性高
  5. 可维护性高
  6. 注释清晰
  7. 文档齐全

常见的coding技巧:

  1. 使用assert
  2. 尽量使用const30. 养成良好的编码风格
  3. 添加必要的注释
  4. 避免编码的陷阱。

注意:

  1. 分析参数的设计(命名,类型),返回值类型的设计
  2. 这里讲解野指针,空指针的危害。
  3. assert的使用,这里介绍assert的作用
  4. 参数部分 const 的使用,这里讲解const修饰指针的作用
  5. 注释的添加

7.编程常见的错误。

  1. 编译型错误
    直接看错误提示信息(双击),解决问题。或者凭借经验就可以搞定。相对来说简单。
  2. 链接型错误
    看错误提示信息,主要在代码中找到错误信息中的标识符,然后定位问题所在。一般是标识符名不
    存在或者拼写错误。
  3. 运行时错误
    借助调试,逐步定位问题。最难搞。

猜你喜欢

转载自blog.csdn.net/qq_74276498/article/details/130784583