【vs2019】调试介绍

文章目录

  • 1. 调试是什么
  • 2. 调试的基本步骤
  • 3. 调试的环境
  • 4. VS2019调试快捷键
  • 5. vs2019调试窗口
  • 6. 写代码的注意事项
    • 6.1 Coding技巧
    • 6.2 assert
    • 6.3 const
  • 7. 实现strcpy,strlen函数
  • 8. 编程常见的错误
    • 8.1 编译型错误
    • 8.2 链接型错误
    • 8.3 运行时错误

1. 调试是什么

调试(debug)是发现和减少计算机程序和电子仪器设备中得程序性错误

2. 调试的基本步骤

  • 发现程序错误的存在
  • 以隔离、消除等方式对错误进行定位
  • 确定错误产生的原因
  • 提出纠正错误的解决办法
  • 对程序错误予以改正,重新测试

3. 调试的环境

并不是在任何环境下都可以进行调试
源程序通常有两种版本

  • Debug版本
  • Release版本

Debug版本称为调试版本,包含调试信息,并且不做任何优化,便于程序员调试程序
Release版本称为发布版本,它往往进行了各种优化,使得程序在代码大小上和运行速度上都是最优的,便于用户使用
只有在Debug版本下,程序才可以进行调试

代码在Debug环境下的结果展示
【vs2019】调试介绍_第1张图片
代码在Release环境下的结果展示
在这里插入图片描述
代码在Debug环境下的反汇编
【vs2019】调试介绍_第2张图片
代码在Release环境下的反汇编
【vs2019】调试介绍_第3张图片

可以看到Release环境下确实会对代码进行优化

那么Release版本和Debug版本究竟进行了哪些优化?

  1. 优化编译选项:Release版本的编译选项通常会启用更多的优化选项,例如去除符号表、优化调试信息、优化代码大小等,这些都有助于减小程序体积、提高程序的运行效率。
  2. 剔除调试代码:Debug版本通常会包含一些额外的调试代码,例如assert、日志输出等,这些代码对程序的运行效率可能会产生一定的影响。在Release版本中,这些调试代码通常会被剔除,从而提高程序的运行效率。
  3. 优化代码结构:在Debug版本中,编译器会生成一些额外的代码,例如调试信息、符号表等,这些代码可能会导致代码结构比较松散。在Release版本中,编译器会进行优化,将代码结构优化得更加紧凑,从而提高程序的运行效率。
  4. 禁用断言:Debug版本通常会包含一些断言代码,这些代码会在程序运行时进行检查,如果检查失败会导致程序崩溃。在Release版本中,这些断言代码通常会被禁用,从而减小程序体积、提高程序的运行效率。

来看下面这个代码在Release版本和Debug版本下有什么不同?

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

Debug版本下是死循环
【vs2019】调试介绍_第4张图片
Release版本下不是死循环
【vs2019】调试介绍_第5张图片

我们观察在Debug版本下的各个变量的地址
【vs2019】调试介绍_第6张图片
【vs2019】调试介绍_第7张图片
我们发现在Debug版本下arr[12]的地址就是i的地址,也就是说arr[12]i是同一个变量,当i==12时,arr[12]=0相当于改变了循环变量,在循环体内改变循环变量的值极有可能发生死循环
我们可以大胆分析以下在Debug模式下变量的内存图如下
【vs2019】调试介绍_第8张图片
在Debug版本下,先定义谁就先开辟谁的空间,至于每个变量之间空多大位置取决于编译器,MSVC编译器变量i的地址比arr[9]的地址多12字节

我们在来观察一下在Release版本下变量的地址
Release版本不能调试,所以用printf打印出来
【vs2019】调试介绍_第9张图片
我们可以推测在Release版本下,内存布局是这样的
【vs2019】调试介绍_第10张图片
在这种特殊情况下,Release版本下编译器会对变量的定义的顺序发生改变,编译器会先定义arr数组,再定义i

注:上面两种版本的内存布局是这样基于两个原因

  1. 定义的局部变量存储在栈区,而栈区空间使用规则是先用高地址,后用低地址
  2. 数组元素随着下标增长,地址由低到高

4. VS2019调试快捷键

F5
未启动调试前,开始调试并跳到第一个间断点(如果有),没有则不会进行调试
启动调试后,跳到下一个间断点(如果有),没有则推出调试
F9
创建断点和取消断点
断点的重要作用,可以在程序的任意位置设置断点。
这样就可以使得程序在想要的位置随意停止执行,继而一步步执行下去。
F10
逐过程,通常用来处理一个过程,一个过程可以是一次函数调用,或者是一条语句。
F11
逐语句,就是每次都执行一条语句,但是这个快捷键可以使我们的执行逻辑进入函数内部(这是最
长用的)。
CTRL + F5
开始执行不调试,如果你想让程序直接运行起来而不调试就可以直接使用。

更多快捷键点我
注:按上述快捷键无效果,则需要同时按住Fn和上述快捷键

这里有一个小技巧,当我们想调试观察循环第n次的情况时,我们可以设置条件断点,条件断点的意思是当满足条件时,才可以跳到断点处
设置方式
1->在循环体内打上断点,并且右击断点【vs2019】调试介绍_第11张图片
2->选择条件选项,并且设置条件,如想直接从第10次循环开始调试,直接将条件设置为i==10
【vs2019】调试介绍_第12张图片
3->按下回车保存
【vs2019】调试介绍_第13张图片
4->开始调试,这样按F5后直接跳到条件断点处,此时的i等于10
【vs2019】调试介绍_第14张图片


5. vs2019调试窗口

注:调试窗口均是在开启调试后才能开启的

1.查看临时变量的值->自动窗口
作用:观察上下文出现过变量的值
打开方式【vs2019】调试介绍_第15张图片
2.查看变量的地址->内存
作用:查看变量的内存信息
【vs2019】调试介绍_第16张图片
打开方式【vs2019】调试介绍_第17张图片
注:若没有内存选项,则需要手动开启
开启方式 工具->选项->调试->打开地址级调试
【vs2019】调试介绍_第18张图片
3.查看调用堆栈->调用堆栈
作用:清晰的反应函数的调用关系以及当前调用所处的位置
【vs2019】调试介绍_第19张图片
打开方式
【vs2019】调试介绍_第20张图片
4.查看程序的汇编代码->反汇编
打开方式:程序开启调试后直接在代码区域右击鼠标,选中反汇编
【vs2019】调试介绍_第21张图片

6. 写代码的注意事项

优秀的代码应该是这样

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

6.1 Coding技巧

  • 使用assert
  • 尽量使用const’
  • 养成良好的编码风格
  • 添加必要的注释
  • 避免编码的陷阱

6.2 assert

【vs2019】调试介绍_第22张图片

assert用来检测一个表达式是不是0,如果表达式是0则调用abort函数终止程序并且在标准错误流上输出一段话,这句话包含值是0的表达式和该程序所在的路径以及assert所在的行数
使用assert需要包含头文件assert.h
【vs2019】调试介绍_第23张图片

我们不能解引用空指针,所以assert可以用来判断该指针是否为空指针

#include 
#include 
int main()
{
	long long* p = (long long*)malloc(sizeof(int) * 100000000l);
	assert(p);
	*p = 10;
	printf("%lld\n", *p);
	return 0;
}

6.3 const

在C语言中,const修饰的变量叫做常变量,它们本质上是变量,只不过具有只读性

  1. const直接修饰变量,无法直接修改变量【vs2019】调试介绍_第24张图片
    可以通过该变量的指针来修改该变量的值
    【vs2019】调试介绍_第25张图片
  2. const修饰指针变量有两种情况
  • const在*前面
    代表const修饰的是指针变量所指向的对象,指向的对象不可以直接修改
    【vs2019】调试介绍_第26张图片
    这样并不是很严谨,因为定义时没有规定a被const修饰的,但是定义指针变量p时又规定了a被const修饰
  • const在*后面
    代表const修饰的是指针变量本身,则这个指针变量不能指向其他的变量
    【vs2019】调试介绍_第27张图片
    可以通过二级指针改变p本身的值
    【vs2019】调试介绍_第28张图片

7. 实现strcpy,strlen函数

【vs2019】调试介绍_第29张图片
【vs2019】调试介绍_第30张图片

8. 编程常见的错误

8.1 编译型错误

直接看错误提示信息(双击),解决问题。或者凭借经验就可以搞定。相对来说比较简单。
【vs2019】调试介绍_第31张图片

8.2 链接型错误

看错误提示信息,主要在代码中找到错误信息中的标识符,然后定位问题所在。一般是函数名不存在或者拼写错误【vs2019】调试介绍_第32张图片
LNK代表LINK链接,说明是链接错误

8.3 运行时错误

借助调试,逐步定位问题

你可能感兴趣的:(C语言,c++,c语言,开发语言)