【实用调试技巧】总是找不到Bug?手把手教你在vs2022中调试程序

个人主页:修修修也

所属专栏:程序调试及报错解决

⚙️操作环境:Visual Studio 2022


目录

什么是Bug?

1947年9月9日:第一个"Bug"被发现

什么是调试?

调试是什么?

调试的基本步骤

Debug和Relese的区别

1.调试的区别

2.文件大小的区别

3.反汇编的区别

4.代码执行结果不同

windows环境下如何进行调试

1.调试环境的准备

2.常用调试快捷键

3.调试时查看程序相关信息

查看临时变量的值

查看单一变量

查看数组成员

查看结构体成员

 查看内存信息

查看调用堆栈

查看汇编信息

第一种方式

第二种方式

查看寄存器

一些练习的例子

实例一:实现代码:求1!+2!+3!+...n!

 实例二

如何写好易于调试的代码

优秀的代码:

常见的Coding技巧:

需要注意学习的点:

编程常见的错误

编译型错误

链接型错误

运行时错误

结语


什么是Bug?

先来看看百度翻译对Bug的解释:

【实用调试技巧】总是找不到Bug?手把手教你在vs2022中调试程序_第1张图片

 而这个让无数程序员感到每天都被噩梦支配的恐惧也有一段有趣的过往:

1947年9月9日:第一个"Bug"被发现

“1947 年 9 月 9 日,我们晚上调试机器的时候,开着的窗户没有纱窗,机器闪烁的亮光几乎吸引来了世界上所有的虫子。果然机器故障了,我们发现了一只被继电器拍死的飞蛾,翅膀大约 4 英寸。”

格蕾丝·霍普(Grace Hopper)用发夹取出飞蛾,把它粘在日志里,并标注:“First actual case of bug being found”(找到了第一个 Bug)。这件计算机史上的奇闻轶事,使“Bug”作为计算机领域的专用词汇,一直沿用至今。

【实用调试技巧】总是找不到Bug?手把手教你在vs2022中调试程序_第2张图片 历史上第一个bug图像

什么是调试?

既然有Bug的存在,那么作为程序员肯定要找Bug并且改Bug.

我们把找Bug的过程叫做调试.

我们在写代码的时候一定多思考,不然很容易像这样:

【实用调试技巧】总是找不到Bug?手把手教你在vs2022中调试程序_第3张图片

不会调试的程序员排查Bug现状:

【实用调试技巧】总是找不到Bug?手把手教你在vs2022中调试程序_第4张图片

 一个高质量的程序员一定要拒绝迷信式改Bug!

【实用调试技巧】总是找不到Bug?手把手教你在vs2022中调试程序_第5张图片


调试是什么?

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


调试的基本步骤

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

Debug和Relese的区别

Debug 通常称为调试版本,它包含调试信息,并且不作任何优化便于程序员调试程序


Release 称为发布版本,它往往是进行了各种优化,使得程序在代码大小和运行速度上都是最优的以便用户很好地使用.

1.调试的区别

在Debug环境下,按F10(有fn键的话,需要按住fn+F10),启动调试,就可以使用如下功能了:

【实用调试技巧】总是找不到Bug?手把手教你在vs2022中调试程序_第6张图片

而在Release环境下,调试不好用,虽然也可以显示调试界面,但是完成不了像debug环境下的操作。


2.文件大小的区别

Debug环境生成的文件,里面因为包含了调试信息,所以占据的空间较大

Release环境下生成的文件,是提供给用户使用不需要用户调试,所以文件所占空间较小

【实用调试技巧】总是找不到Bug?手把手教你在vs2022中调试程序_第7张图片

【实用调试技巧】总是找不到Bug?手把手教你在vs2022中调试程序_第8张图片


3.反汇编的区别

Debug:较多

【实用调试技巧】总是找不到Bug?手把手教你在vs2022中调试程序_第9张图片

 Release:较少

【实用调试技巧】总是找不到Bug?手把手教你在vs2022中调试程序_第10张图片


4.代码执行结果不同

如下代码:

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

Debug环境下,结果是死循环:

【实用调试技巧】总是找不到Bug?手把手教你在vs2022中调试程序_第11张图片

但在Release环境下却输出了13个"hello":

【实用调试技巧】总是找不到Bug?手把手教你在vs2022中调试程序_第12张图片

造成该结果的原因主要是Release环境会优化代码,使程序列在代码大小和运行速度上达到最优,以便用户能够很好地使用它。


windows环境下如何进行调试

1.调试环境的准备

首先我们要在编译器中选择Debug选项,才可以进行正常调试:

【实用调试技巧】总是找不到Bug?手把手教你在vs2022中调试程序_第13张图片


2.常用调试快捷键

【实用调试技巧】总是找不到Bug?手把手教你在vs2022中调试程序_第14张图片

vs2022中找到调试按钮,鼠标放上去就可以看到可以进行的操作及其快捷键.

常用快捷键有:

F5

启动调试,经常用来直接跳到下一个断点处.


F9

创建断点和取消断点
断点的重要作用,可以在程序的任意位置设置断点。
这样就可以使得程序在想要的位置随意停止执行,继而一步步执行下去.


F10

逐过程,通常用来处理一个过程,一个过程可以是一次函数调用,或者是一条语句。


 

F11

逐语句,就是每次都执行一条语句,但是这个快捷键可以使我们的执行逻辑进入函数内部(这是最常用的)


 

Ctrl+F5

开始执行不调试,如果你想让程序直接运行起来而不调试就可以直接使用

想知道更多快捷键?VS中常用的快捷键大全


3.调试时查看程序相关信息

查看临时变量的值

查看单一变量

当我们需要观察临时变量的值时,可以先按下F10/F11进入调试,然后在调试中选择:调试-窗口-监视-监视1,就可以打开监视窗口了.

【实用调试技巧】总是找不到Bug?手把手教你在vs2022中调试程序_第15张图片

然后在监视窗口输入想观察的变量,敲下回车就可以观察这个变量了.

【实用调试技巧】总是找不到Bug?手把手教你在vs2022中调试程序_第16张图片


查看数组成员

当我们需要观察数组中的成员时,可以输入"数组名,大小",然后点击旁边的小三角可以一次性查看全部的数组成员了.

【实用调试技巧】总是找不到Bug?手把手教你在vs2022中调试程序_第17张图片

【实用调试技巧】总是找不到Bug?手把手教你在vs2022中调试程序_第18张图片


查看结构体成员

当我们需要观察结构体中的成员时,可以输入结构体名,然后点击旁边的小三角可以一次性查看全部的结构体成员了.

【实用调试技巧】总是找不到Bug?手把手教你在vs2022中调试程序_第19张图片


 查看内存信息

调试开始之后(按下F10/F11)后,用于观察内存信息.

【实用调试技巧】总是找不到Bug?手把手教你在vs2022中调试程序_第20张图片

内存窗口如下:

【实用调试技巧】总是找不到Bug?手把手教你在vs2022中调试程序_第21张图片

 如果不习惯看16列的数的话,也可以选择将它改为4列:

【实用调试技巧】总是找不到Bug?手把手教你在vs2022中调试程序_第22张图片

【实用调试技巧】总是找不到Bug?手把手教你在vs2022中调试程序_第23张图片 【实用调试技巧】总是找不到Bug?手把手教你在vs2022中调试程序_第24张图片

观察内存可以直接输入地址观察,也可以写取地址表达式观察:

【实用调试技巧】总是找不到Bug?手把手教你在vs2022中调试程序_第25张图片

【实用调试技巧】总是找不到Bug?手把手教你在vs2022中调试程序_第26张图片

这样输入它然后敲回车就可以直接带你找到该变量在内存中的位置:

【实用调试技巧】总是找不到Bug?手把手教你在vs2022中调试程序_第27张图片


查看调用堆栈

通过调用堆栈,可以清晰的反应函数的调用关系以及当前调用所处的位置.

【实用调试技巧】总是找不到Bug?手把手教你在vs2022中调试程序_第28张图片


查看汇编信息

在调试开始之后,有两种方式转到汇编.

第一种方式

在空白区右击鼠标,选择"转到反汇编":

【实用调试技巧】总是找不到Bug?手把手教你在vs2022中调试程序_第29张图片

然后就可以查看汇编信息了:

【实用调试技巧】总是找不到Bug?手把手教你在vs2022中调试程序_第30张图片

第二种方式

在调试开始后,点击"调试-窗口-反汇编"即可查看汇编信息.

【实用调试技巧】总是找不到Bug?手把手教你在vs2022中调试程序_第31张图片

效果如下:

【实用调试技巧】总是找不到Bug?手把手教你在vs2022中调试程序_第32张图片


查看寄存器

进入调试后,点击"调试-窗口-寄存器"即可查看当前运行环境的寄存器的使用信息.

【实用调试技巧】总是找不到Bug?手把手教你在vs2022中调试程序_第33张图片


一些练习的例子

师傅领进门,修行靠个人.下面有几个可以调试的例子,大家可以拷贝进自己的编辑器边调试边分析这些代码的问题到底出在哪里.

实例一:实现代码:求1!+2!+3!+...n!

int main()
{
	int i = 0;
	int sum = 0;//保存最终结果
	int n = 0;
	int ret = 1;//保存n的阶乘
	scanf("%d", &n);
	for (i = 1; i <= n; i++)
	{
		int j = 0;
		for (j = 1; j <= i; j++)
		{
			ret *= j;
		}
		sum += ret;
	}
	printf("%d\n", sum);
	return 0;
}

不考虑溢出的情况下,这时候我们如果输入3,期待输出9,但实际输出的是15.

在调试中我希望大家可以搞清楚:为什么会这样?哪一步出了问题?如何解决?


 实例二

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

 这个例子我希望大家可以结合查看内存信息以及查看变量的方法来找出让程序陷入死循环的原因.


如何写好易于调试的代码

优秀的代码:

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

常见的Coding技巧:

  1. 使用assert (如果有不太清楚assert函数用法的可以移步这篇博客:不想改bug?程序员必须学会使用的报错函数assert!(断言函数详解))
  2. 尽量使用const
  3. 养成良好的编码风格
  4. 添加必要的注释
  5. 避免编码的陷阱

 多看和学习大佬是如何编写优秀的代码的,如下面是一个模拟实现库函数strcpy的代码:

/***
*char *strcpy(dst, src) - copy one string over another
*
*Purpose:
* Copies the string src into the spot specified by
* dest; assumes enough room.
*
*Entry:
* char * dst - string over which "src" is to be copied
* const char * src - string to be copied over "dst"
*
*Exit:
* The address of "dst"
*
*Exceptions:
*******************************************************************************/
char* strcpy(char* dst, const char* src)
{
	char* cp = dst;
	assert(dst && src);
	while (*cp++ = *src++)
		; /* Copy src over dst */
	return(dst);
}

需要注意学习的点:

  1. 分析参数的设计(命名,类型),返回值类型的设计
  2. assert的使用.(如果有不太清楚assert函数用法的可以移步这篇博客:不想改bug?程序员必须学会使用的报错函数assert!(断言函数详解))
  3. 野指针,空指针
  4. const的使用
  5. 注释的添加

编程常见的错误

编译型错误

直接看错误提示信息(双击),解决问题。或者凭借经验就可以搞定。相对来说简单。

链接型错误

看错误提示信息,主要在代码中找到错误信息中的标识符,然后定位问题所在。

一般是标识符名不存在或者拼写错误。

运行时错误

借助调试,逐步定位问题。


结语

没有什么技能是天生就会的,都是通过后天的不断学习和练习最终掌握的,希望大家可以做一个有心人,积累排错经验。也祝大家"0 Error 0 Warning",Bug全Free!希望这篇博客能对大家有所帮助,一起学习,一起进步!

相关文章推荐

有关“函数用于调用的参数太少”问题解决办法

【C语言】结构体的大小是如何计算的?(结构体对齐)

......



你可能感兴趣的:(程序调试及报错解决,bug,c语言,学习,笔记,开发语言,调试)