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

news2025/1/17 21:55:17

🦄个人主页:修修修也

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

⚙️操作环境: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的解释:

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

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

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

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

历史上第一个bug图像

什么是调试?

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

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

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

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

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


调试是什么?

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


调试的基本步骤

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

Debug和Relese的区别

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


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

1.调试的区别

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

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


2.文件大小的区别

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

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


3.反汇编的区别

Debug:较多

 Release:较少


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环境下,结果是死循环:

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

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


windows环境下如何进行调试

1.调试环境的准备

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


2.常用调试快捷键

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

常用快捷键有:

F5

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


F9

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


F10

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


 

F11

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


 

Ctrl+F5

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

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


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

📌查看临时变量的值

🎏查看单一变量

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

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


🎏查看数组成员

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


🎏查看结构体成员

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


 📌查看内存信息

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

内存窗口如下:

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

 

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

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


📌查看调用堆栈

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


📌查看汇编信息

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

🎏第一种方式

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

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

🎏第二种方式

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

效果如下:


📌查看寄存器

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


一些练习的例子

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

实例一:实现代码:求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 <stdio.h>
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语言】结构体的大小是如何计算的?(结构体对齐)

......



本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1096073.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

13 | 如何正确使用 @Entity 里面的回调方法

Java Persistence API 里面规定的回调方法有哪些&#xff1f; JPA 协议里面规定&#xff0c;可以通过一些注解&#xff0c;为其监听回调事件、指定回调方法。下面我整理了一个回调事件注解表&#xff0c;分别列举了 PrePersist、PostPersist、PreRemove、PostRemove、PreUpdat…

线性排序:如何根据年龄给100万用户数据排序?

文章来源于极客时间前google工程师−王争专栏。 桶排序、计数排序、基数排序时间复杂度是O(n)&#xff0c;所以这类排序算法叫作线性排序。 线性的原因&#xff1a;三个算法是非基于比较的排序算法&#xff0c;都不涉及元素之间的比较操作。 三种排序对排序的数据要求苛刻&am…

19 | 如何搞清楚事务、连接池的关系?正确配置是怎样的

事务的基本原理 在学习 Spring 的事务之前&#xff0c;你首先要了解数据库的事务原理&#xff0c;我们以 MySQL 5.7 为例&#xff0c;讲解一下数据库事务的基础知识。 我们都知道 当 MySQL 使用 InnoDB 数据库引擎的时候&#xff0c;数据库是对事务有支持的。而事务最主要的作…

(转)富文本编辑器——Vue2Editor

介绍 Vue2Editor是一个简单易用且功能强大的Vue版本的富文本编辑器&#xff0c;其基于Quill.js和Vuejs构建&#xff01; 简单易用、功能强大的富文本编辑器——Vue2Editor Github https://github.com/davidroyer/vue2-editor 特性 简单易用&#xff1b;基于Vue.js & Quil…

【Golang】Go的并发和并行性解释。谁说Go不是并行语言?

偶然发现百度上有很多"师出同门"的"go是并发语言&#xff0c;而不是并行语言"的说法。让我顿感奇怪&#xff0c;"并行"说白了就是对CPU多核的利用&#xff0c;这年头不能利用多核的编译语言还有的混&#xff1f;而且还混的这么好&#xff1f;并且…

Linux网络编程系列之服务器编程——非阻塞IO模型

Linux网络编程系列 &#xff08;够吃&#xff0c;管饱&#xff09; 1、Linux网络编程系列之网络编程基础 2、Linux网络编程系列之TCP协议编程 3、Linux网络编程系列之UDP协议编程 4、Linux网络编程系列之UDP广播 5、Linux网络编程系列之UDP组播 6、Linux网络编程系列之服务器编…

echarts关于一次性绘制多个饼图 (基于vue3)

在echarts中&#xff0c;dataset 和 source 是用来配置数据的选项。 dataset 是一个包含数据相关配置的对象&#xff0c;用于指定数据的来源和格式。它可以包含多个维度的数据集&#xff0c;每个维度都可以有自己的名称和数据。 source 是 dataset 中的一个子项&#xff0c;用于…

图计算(林子雨慕课课程)

文章目录 13. 图计算13.1 图计算简介13.2 Pregel简介13.3 Pregel图计算模型13.3.1 有向图和顶点13.3.2 Pregel的计算过程13.3.2 Pregel实例 13.4 Pregel的C API13.4.1 定义Vertex基类13.4.2 消息传递机制和Combiner13.4.3 Aggregator、拓扑改变和输入输出 13.5 Pregel的体系结构…

【通过实验带你认识linux下的源码编译】

通过实验带你认识linux下的源码编译 01 初识项目编译02 编译过程03 完整的编译过程1、创建源代码文件2、创建configure脚本3、创建Makefile.am 源代码是相对目标代码和可执行代码而言的。源代码是用汇编语言和高级语言写出来的代码。 目标代码是指源代码经过编译程序产生的能被…

qml介绍

文章目录 qml简介对象一个风车的例子 qml简介 从 Qt 4.7 开始&#xff0c;Qt 引入了一种声明式脚本语言&#xff0c;称为 QML&#xff08;Qt Meta Language 或者 Qt Modeling Language&#xff09;&#xff0c;作为 C 语言的一种替代。而 Qt Quick 就是使用 QML 构建的一套类库…

(latex中appendix附录怎么写)以及(附录里面的图片表格之类的如何重新编号)

文章目录 初级&#xff1a;怎么写进阶&#xff1a;怎么重新编号进阶&#xff1a;怎么换成单栏格式 初级&#xff1a;怎么写 这个很简单&#xff0c;我一开始以为很复杂。 \begin{document} #这里是“正文”。 #这里是“引用”。 #下面开始是附录。 \appendix \section{Proofs…

英语——分享篇——每日100词——801-900

medical——adj.医疗的——me我(熟词)di弟(拼音)cal擦了(拼音) chief——n.酋长——thief小偷——小偷拜见酋长 pork——n.猪肉——p皮鞋(编码)or偶人(拼音)k机关枪(编码)——穿着皮鞋的偶人扛着机关枪挑猪肉 pie——n.馅饼&#xff0c;派——瞥——他无意瞥见一块馅饼 saus…

GB28181平台简介

产品简介 LiveMedia视频中间件是支持部署到本地服务器或者云服务器的纯软件服务&#xff0c;也提供服务器、GPU一体机全包服务&#xff0c;提供视频设备管理、无插件、跨平台的实时视频、历史回放、语音对讲、设备控制等基础功能&#xff0c;支持视频协议有海康、大华私有协议…

Golang学习记录:基础篇练习(一)

Golang学习记录&#xff1a;基础篇练习&#xff08;一&#xff09; 1、九九乘法表2、水仙花数3、斐波那契数列4、编写一个函数&#xff0c;求100以内的质数5、统计字符串里面的字母、数字、空格以及其他字符的个数6、二维数组对角线的和7、冒泡排序算法8、选择排序算法9、二分查…

JDK 19 协程新特性学习

目录 一、协程定义 二、协程发展史 &#xff08;一&#xff09;协程的基本发展史说明 &#xff08;二&#xff09;Java协程发展说明 三、JDK 19 协程的原理细节 &#xff08;一&#xff09;Thread.ofVirtual().start() &#xff08;二&#xff09;SocketChannel.write(…

没有前端如何测试后端跨域问题

一、问题 前段时间对项目中的跨域做了相关的处理&#xff0c;网上有很多跨域的解决方案。前端解决&#xff0c;后端解决&#xff0c;nginx代理解决。我采用的是在后端中使用Cors来解决跨域的问题。但是前端项目还没有搭建起来&#xff0c;并不知道Cors的解决方案是否会生效&am…

揭秘元宇宙背后最炫科技风:数字经济时代,元宇宙发展解决方案及核心技术

文章目录 前言一、关于“元宇宙”业界趋势1.1、元宇宙的概念与发展历程1.2、行业应用体验向虚实融合和实时互动演进1.3、数字内容成为各行业 3D 数字世界入口 二、对于元宇宙发展的解决方案和实践2.1、MetaStudio 构建场景化全栈能力2.2、企业 3D 空间&#xff0c;围绕 4 类场景…

PyQt界面里如何加载本地视频以及调用摄像头实时检测(小白入门必看)

目录 1.PyQt介绍 2.代码实现 2.1实时调用摄像头 2.2 使用YOLOv5推理 2.3 代码中用到的主要函数 1.PyQt介绍 PyQt是一个用于创建桌面应用程序的Python绑定库&#xff0c;它基于Qt框架。Qt是一个跨平台的C应用程序开发框架&#xff0c;提供了丰富的图形界面、网络通信、数据…

Qt项目通过.pri文件将众多文件按功能模块分类显示,开发大型项目必备

Qt项目通过.pri文件将众多文件按功能模块分类显示&#xff0c;开发大型项目必备 Chapter1 Qt项目通过.pri文件将众多文件按功能模块分类显示&#xff0c;开发大型项目必备($$$)Chapter2 在Qt项目中添加pri文件前言创建pri文件的步骤一、创建Qt项目二、创建pri空文件三、调试 Ch…

SpringCloud学习笔记-Nacos服务分级存储模型

Nacos服务分级存储模型 一级是服务&#xff0c;例如userservice二级是集群&#xff0c;例如杭州或上海三级是实例&#xff0c;例如杭州机房的某台部署了userservice的服务器 微服务互相访问时&#xff0c;应该尽可能访问同集群实例&#xff0c;因为本地访问速度更快。当本集…