当前位置: 首页 > news >正文

VS实用调试技巧

一.什么是BUG🐛

Bug一词的原意是虫子,而在电脑系统或程序中隐藏着的一些未被发现的缺陷或问题,人们也叫它"bug"。这是为什么呢?这就要追溯到一个程序员与飞蛾的故事了。

Bug的创始人格蕾丝·赫柏(Grace Murray Hopper),是一位为美国海军工作的电脑专家,也是最早将人类语言融入到电脑程序的人之一。而代表电脑程序出错的“bug” 这名字,正是由赫柏所取的。1947年9月9日,赫柏对Harvard Mark II设置好17000个继电器进行编程后,技术人员正在进行整机运行时,它突然停止了工作。于是他们爬上去找原因,发现这台巨大的计算机内部一组继电器的触点之间有一只飞蛾,这显然是由于飞蛾受光和热的吸引,飞到了触点上,然后被高电压击死。所以在报告中,赫柏用胶条贴上飞蛾,并把“bug”来表示“一个在电脑程序里的错误”,“Bug”这个说法一直沿用到今天。

格蕾丝·赫柏的报告

二.调试及其重要性📝

2.1 什么是调试

所有发生的事情都一定有迹可循,如果问心无愧,就不需要掩盖也就没有迹象了,如果问心有愧,就必然需要掩盖,那就一定会有迹象,迹象越多就越容易顺藤而上,这就是推理的途径。顺着这条途径顺流而下就是犯罪,逆流而上,就是真相。

而我们程序员就好比一个侦探,一个用来寻找bug,修改bug的侦探。人们将这个过程叫做"Debug"(中文称作"调试"),意即"捉虫子"或"杀虫子"。每一次调试都是尝试破案的过程。

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

2.2 调试的基本步骤

  • 发现程序错误的存在

  • 以隔离、消除等方式对错误进行定位

  • 确定错误产生的原因

  • 提出纠正错误的解决办法

  • 对程序错误予以改正,重新测试

本文将详细介绍在windows系统的VS环境下的调试过程。

2.3 Debug与Release的介绍

在VS中,我们会发现我们的程序可以在两个环境下运行,这两个环境就是Debug版本和Release版本,它们二者有何区别呢?

VS中的Debug与Release

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

我们可以分别在两种环境下编译代码生成对应的可执行程序如下:

显然,Release版本的可执行文件比Debug版本的小很多,说明编译器对其作了优化。

因此,我们日常所说的调试是在Debug版本的环境下进行的,这是因为Release版本无法进行调试,其调试信息被编译器优化了。而对于测试人员来说,由于要站在用户的角度上来测试程序是否能正常使用,因此测试是在Release版本的环境下进行的


那么,Release版本下编译器可能会做什么优化呢?请看如下代码:

#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环境下我们发现程序并没有崩溃而是陷入了死循环:

我们运行调试代码转到反汇编如下:

我们知道,数据在栈上的开辟是从高地址向低地址处开辟的,因此在Debug环境下变量i的地址比数组arr的地址高。而在数组内部数据的存储是从低地址向高地址的,因此首元素地址arr是在数组所在空间的低位,如下:

我们很惊讶的发现(arr+12)就是变量i的地址。当循环过程中i等于12时,此时将arr[i]改为0就等价于将i的值修改为0,然后i++后i等于1小于12,继续进行循环,依次反复形成了死循环。如下:

整个过程简化图如下:


而在Release版本的环境下程序并不会出现死循环的问题:

我们可以打印出此时变量i和数组在栈上的地址如下:

我们发现此时变量i被编译器优化到低地址处,arr[12]存储的值就不是i了,便不会出现死循环的情况。

综上,以上代码在Release版本下,编译器使变量在内存中开辟的顺序发生了变化,影响到了程序执行的结果,这便是优化带来的好处。

三.windows环境下调试介绍✨

首先第一步,我们需要将环境切换为Debug版本,才能进行调试

3.1 常用快捷键介绍

以下是在调试过程中最为常用的几个快捷键:

快捷键

功能

Ctrl+F5

开始执行而不进行调试。用于想让程序直接运行起来而不调试时。

F9

作用:创建断点和取消断点

断点:可以使程序在任何你想停下的地方停止执行,继而一步步执行下去。我们可以在任何地方设置断点,一个程序也可以有多个断点

F10

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

F11

逐语句,每次只执行一条语句,我们可以通过这个快捷键使我们的执行逻辑进入函数内部(这是F10所不具备的,F11是我们在调试过程中最常用的)

F5

启动调试到下一断点处,需要配合F9进行使用,如果程序没有断点则无异于Ctrl+F5

快捷键用法

我们还可以对某一断点设置停止条件,方法是右键断点->单击条件->输入断点条件->关闭
例如:我们需要让程序停止在第4次循环处,我们可以输入i==4
此时单击F5运行到断点,我们查看自动窗口发现程序在停止时i的值为4

3.2 在调试过程中查看程序当前信息

开启调试后,我们可以在VS上方的调试->窗口看到许多用来查看数据信息的窗口:

3.3.1 监视窗口

通过监视窗口我们可以查看我们想要查看的变量甚至是表达式的值在程序运行过程中的变化,十分灵活,这是我们调试中用得最多的窗口之一。如下:

3.3.2 自动窗口

打开自动窗口后,编译器会将一些可能需要观察的变量显示在窗口中,较为方便。其缺陷是可能无法显示我们真正需要观察的变量,并且无法灵活显示表达式等的值。如下:

3.3.3 监视窗口

打开局部变量变量窗口,会将程序中的所有局部变量全部显示出来。如下:

3.3.4 调用堆栈窗口

通过调用堆栈,可以清晰的反应函数的调用关系以及当前调用所处的位置。如下:
通过调用堆栈窗口,我们可以发现,show函数栈帧在main函数栈帧之上,即show函数是由main函数调用的。并且可以看出此时show函数运行到第20行。

3.3.5 内存窗口

通过内存窗口我们可以看到内存中的信息,可以观察变量在内存中的存储情况。如下:

3.3.6 反汇编

我们可以查看当前程序转化后的汇编代码,进而从更底层的角度观察程序的执行过程。如下:

3.3.7 寄存器

通过寄存器窗口,我们可以观察在当前环境下CPU内的寄存器的使用信息,如ebp栈底寄存器、esp栈顶寄存器等等。

3.3 调试实例

我们上面通过调试分析了数组越界陷入死循环的问题。下面,我们再通过一道实例来掌握调试的技巧:

实现代码:求 1!+2!+3! ...+ n! ;不考虑溢出。我们可能会写出以下代码:
#include<stdio.h>
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:
是什么问题导致出错了呢?这就需要我们动手进行调试。在调试之前我们可以先预测问题的所在,比如算阶乘时出错求和时出错等等。做到心里有数,而不是盲目的进行调试。

我们可以在ret*=j处设置一个断点,打开监视窗口监视ret和sum观察每个数阶乘的值和累加后的值,如下:

我们单击F10逐过程执行,当外层循环i的值为3时,即计算3的阶乘时,我们发现ret的初始值并非为1,而是2的阶乘。此时再计算3的阶乘,就是2*1*2*3=12 != 6,结果出错:

最后sum+ret的值就为15,与我们的输出相符:

可见,每次在求阶乘时,我们都应该把ret重置为1,正确的代码如下:

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;ret = 1; //将ret置1for (j = 1; j <= i; j++){ret *= j;}sum += ret;}printf("%d\n", sum);return 0;
}

3.4 实践出真知

  • 任何事情都不可能一蹴而就,一定要多加练习,才能熟练掌握调试技巧。

  • 一个初学者可能80%的时间在写代码,20%的时间在进行调试;而一个程序员,可能80%的时间在进行调试,剩余20%的时间才是在写代码。

  • 随之学习的深入,后续可能会出现很多更加复杂的调试场景,如多线程等。只有打好基础,在未来才能融会贯通,利于不败之地。

  • 多多使用快捷键可以很大程度上提高效率。

四.如何写出便于调试的优秀代码👑

4.1 什么是优秀的代码

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

4.2 常用coding(编码)技巧

1.多使用assert断言,可以告知你出错的位置
2.尽量使用const,避免意外修改
3.养成良好的编码风格
4.添加必要的注释
5.避免编码的陷阱

4.3 实例

试模拟实现一个strcpy函数,尽量用到上述的编码技巧。如下:
char* strcpy(char* dst, const char* src) //const修饰防止对源字符串进行修改
{assert(dst && src); //避免传入空指针char cur = dst; //保存起始位置//将src的字符一个个拷贝到det中,包括'\0'while ((*dst++ = *src++)!='\0'){;}return cur; //返回目标字符串,以便链式访问
}

五.编程中常见的错误👀

5.1 编译型错误

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

5.2 链接型错误

链接期间出现的错误。看错误提示信息,主要在代码中找到错误信息中的标识符,然后定位问题所在。一般是标识符名不存在或者拼写错误

5.3 运行时出错

运行期间出现的错误。借助调试,逐步定位问题。最难搞的一种错误

不要害怕遇到错误,每出现一次的错误就是一次突破自我的机会。
学会积累排错经验,勇于尝试。不经风雨🌂,怎能见彩虹🌈

以上,就是本期的全部内容啦🌸

制作不易,能否点个赞再走呢🙏

相关文章:

VS实用调试技巧

一.什么是BUG&#x1f41b;Bug一词的原意是虫子&#xff0c;而在电脑系统或程序中隐藏着的一些未被发现的缺陷或问题&#xff0c;人们也叫它"bug"。这是为什么呢&#xff1f;这就要追溯到一个程序员与飞蛾的故事了。Bug的创始人格蕾丝赫柏&#xff08;Grace Murray H…...

通俗易懂理解三次握手、四次挥手(TCP)

文章目录1、通俗语言理解1.1 三次握手1.2 四次挥手2、进一步理解三次握手和四次挥手2.1 三次握手2.2 四次挥手1、通俗语言理解 1.1 三次握手 C:客户端 S&#xff1a;服务器端 第一次握手&#xff1a; C&#xff1a;在吗&#xff1f;我要和你建立连接。 第二次握手&#xff…...

1.1 什么是并发

1.1 什么是并发 并发&#xff1a;指两个或更多独立的活动同时发生。并发在生活中随处可见。我们可以一边走路一边说话&#xff0c;也可以两只手同时做不同的动作。 1.1.1 计算机系统中的并发 当我们提到计算机术语的“并发”&#xff0c;指的是在单个系统里同时执行多个独立…...

万字讲解你写的代码是如何跑起来的?

今天我们来思考一个简单的问题&#xff0c;一个程序是如何在 Linux 上执行起来的&#xff1f; 我们就拿全宇宙最简单的 Hello World 程序来举例。 #include <stdio.h> int main() {printf("Hello, World!\n");return 0; } 我们在写完代码后&#xff0c;进行…...

034.Solidity入门——21不可变量

Solidity 中的不可变量是在编译时就被确定的常量&#xff0c;也称为常量变量&#xff08;constant variable&#xff09;或只读变量&#xff08;read-only variable&#xff09;。这些变量在定义时必须立即初始化&#xff0c;并且在整个合约中都无法被修改&#xff0c;可以在函…...

Vulnhub 渗透练习(四)—— Acid

环境搭建 环境下载 kail 和 靶机网络适配调成 Nat 模式&#xff0c;实在不行直接把网络适配还原默认值&#xff0c;再重试。 信息收集 主机扫描 没扫到&#xff0c;那可能端口很靠后&#xff0c;把所有端口全扫一遍。 发现 33447 端口。 扫描目录&#xff0c;没什么有用的…...

C++ 在线工具

online编译器https://godbolt.org/Online C Compiler - online editor (onlinegdb.com) https://www.onlinegdb.com/online_c_compilerC Shell (cpp.sh) https://cpp.sh/在线文档Open Standards (open-std.org)Index of /afs/cs.cmu.edu/academic/class/15211/spring.96/wwwC P…...

使用MMDetection进行目标检测、实例和全景分割

MMDetection 是一个基于 PyTorch 的目标检测开源工具箱&#xff0c;它是 OpenMMLab 项目的一部分。包含以下主要特性&#xff1a; 支持三个任务 目标检测&#xff08;Object Detection&#xff09;是指分类并定位图片中物体的任务实例分割&#xff08;Instance Segmentation&a…...

使用ThreadLocal实现当前登录信息的存取

有志者&#xff0c;事竟成 文章持续更新&#xff0c;可以关注【小奇JAVA面试】第一时间阅读&#xff0c;回复【资料】获取福利&#xff0c;回复【项目】获取项目源码&#xff0c;回复【简历模板】获取简历模板&#xff0c;回复【学习路线图】获取学习路线图。 文章目录一、使用…...

高通平台开发系列讲解(Android篇)AudioTrack音频流数据传输

文章目录 一、音频流数据传输通道创建1.1、流程描述1.2、流程图解二、音频数据传输2.1、流程描述2.2、流程图解沉淀、分享、成长,让自己和他人都能有所收获!😄 📢本篇章主要图解AudioTrack音频流数据传输 。 一、音频流数据传输通道创建 1.1、流程描述 AudioTrack在set函…...

BUUCTF-firmware1

题目下载&#xff1a;下载 新题型&#xff0c;记录一下 题目给出了flag形式&#xff0c;md5{网址&#xff1a;端口}&#xff0c;下载发现是一个.bin文件 二进制文件&#xff0c;其用途依系统或应用而定。一种文件格式binary的缩写。一个后缀名为".bin"的文件&#x…...

【C++之容器篇】二叉搜索树的理论与使用

目录前言一、二叉搜索树的概念二、二叉搜素树的模拟实现&#xff08;增删查非递归实现&#xff09;1. 二叉搜素树的结点2. 二叉搜索树的实现&#xff08;1&#xff09;. 二叉搜索树的基本结构&#xff08;2&#xff09;构造函数&#xff08;3&#xff09;查找函数&#xff08;4…...

爬虫神级解析工具之XPath:用法详解及实战

一、XPATH是什么 Xpath最初被设计用来搜寻XML文档,但它同样适用于HTML文档的搜索。通过简洁明了的路径选择表达式,它提供了强大的选择功能;同时得益于其内置的丰富的函数,它可以匹配和处理字符串、数值、时间等数据格式,几乎所有节点我们都可以通过Xpath来定位。 在Pyth…...

Markdown编辑器

这里写自定义目录标题欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题&#xff0c;有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个自定义列表如何创建一个注…...

数据结构<堆>

&#x1f387;&#x1f387;&#x1f387;作者&#xff1a; 小鱼不会骑车 &#x1f386;&#x1f386;&#x1f386;专栏&#xff1a; 《数据结构》 &#x1f393;&#x1f393;&#x1f393;个人简介&#xff1a; 一名专科大一在读的小比特&#xff0c;努力学习编程是我唯一…...

Linux下Socket编程利用多进程实现一台服务器与多台客户端并发通信

文章目录前言一、服务器 server二、客户端 client三、并发通信演示四、程序源码前言 前些日子同“ Linux应用编程 ”专栏中发布过的TCP及UDP在Linux或Windows下的通信都为单进程下的Socket编程&#xff0c;若还存在一些套接字相关函数模糊不清&#xff0c;读者可移步“Socket编…...

【MySQL】数据库基础

目录 1、什么是数据库 2、 数据库基本操作 2.1 查看当前数据库 2.2 创建一个数据库 2.3 选中数据库 2.4 删除数据库 3、常见的数据类型 3.1 数值类型 3.2 字符串类型 3.3 日期类型 4、表的操作 4.1 创建表 4.2 查看指定数据库下的所有表 4.3 查看表的结构 4.…...

Microsoft Office 2021 / 2019 Direct Download Links

前言 微软Office在很长一段时间内都是最常用和最受欢迎的软件。从小型创业公司到大公司,它的使用比例相当。它可以很容易地从微软的官方网站下载。但是,微软只提供安装程序,而不提供完整的软件供下载。这些安装文件通常比较小。下载并运行后,安装的文件将从后端服务器安装M…...

XX 系统oracle RAC+ADG 数据库高可用容灾演练记录

停止备库监听&#xff0c;避免强制关机时切换到备库 su - grid lsnrctl stop 主库高可用重启测试 /u01/app/19c/grid/bin/crsctl stop crs sync;sync;reboot --/u01/app/19c/grid/bin/crsctl start crs 机器重启后自动起的 /u01/app/19c/grid/bin/crsctl stat res -t 主库容…...

JSP与Servlet

一、什么是JSP? JSP(java Service Pages)是由Sun Microsystems公司倡导、许多公司参与一起建立的动态技术标准。 在传统的HTML文件(*.htm 、 *.html)中加入Java程序片段&#xff08;Scriptlet&#xff09;和JSP标签&#xff0c;构成了JSP网页。 1.1 JSP页面的运行原理 客户…...

C++之迭代器

迭代器C中&#xff0c;迭代器就是类似于指针的对象&#xff0c;但比指针的功能更丰富&#xff0c;它提供了对对象的间接访问&#xff0c;每个迭代器对象代表容器中一个确定的地址。举个例子&#xff1a;void test() {vector<int> vv{1,2,3,4,5};for(vector<int>::i…...

2023-02-16:干活小计

数学公式表示学习&#xff1a; 大约耗时&#xff1a;2 hours 在做了一些工作后重读论文&#xff1a;MathBERT: A Pre-Trained Model for Mathematical Formula Understanding 这是本篇论文最重要的idea&#xff1a;Current pre-trained models neglect the structural featu…...

Linux上安装LaTeX

Linux上安装LaTeX1. 安装1.1 下载安装texlive1.2 配置中文1.3 安装XeLatex1.4 安装编辑器1.5 设置默认支持中文编译1.6 配置环境路径2. latex配置2.1 latex自动安装宏包2.2 latex手动安装宏包2.2.1. 查找包2.2.2. 生成.sty文件2.2.3. 复制到配置文件夹3. 更新包3. 卸载参考链接…...

webpack -- 无法将“webpack”项识别为 cmdlet

webpack : 无法将“webpack”项识别为 cmdlet、函数、脚本文件或可运行程序的名称。请检查名称的拼写&#xff0c;如果包括路径&#xff0c;请确保路径正确&#xff0c;然后再试一次。 1.检测是否是版本太高而只能使用脚手架进行打包 webpack4.x的打包已经不能用webpack 文件a …...

对齐与非对齐访问

对齐与非对齐访问 什么是非对齐访问 在机器指令层面&#xff0c;当尝试从不能被 N 整除 (addr % N ! 0) 的起始地址读取 N 字节的数据时即发生了非对齐内存访问。举例而言&#xff0c;从地址 0x10004 读取 4 字节是可以的&#xff0c;然而从地址 0x10005 读取 4 字节数据将会…...

基于感知动作循环的层次推理用于视觉问答

title&#xff1a;Hierarchical Reasoning Based on Perception Action Cycle for Visual Question Answering 基于感知动作循环的层次推理用于视觉问答 文章目录title&#xff1a;[Hierarchical Reasoning Based on Perception Action Cycle for Visual Question Answering](…...

python中的.nc文件处理 | 05 NetCDF数据的进一步分析

​ NetCDF数据的进一步分析 比较不同数据集、不同季节的气候数据 import os import numpy as np import pandas as pd import matplotlib.pyplot as plt import cartopy.crs as ccrs import cartopy.feature as cfeature import seaborn as sns import geopandas as gpd import…...

GGX发布全新路线图,揭示具备 Layer0 特性且可编程的跨链基建生态

据彭博社报道&#xff0c;具备跨链通信且可编程的 Layer0 基础设施协议 Golden Gate (GGX) 已进行了 两年的线下开发&#xff0c;于近日公开发布了最新的路线图&#xff0c;该路线图不仅显示了该生态在过去两年的发展历程&#xff0c;也披露了 2023 年即将实现的重要里程碑。 G…...

taro+vue3 搭建一套框架,适用于微信小程序和H5

这里写tarovue3 搭建一套框架&#xff0c;适用于微信小程序和H5TaroVue3 搭建适用于微信小程序和 H5 的框架的大致步骤&#xff1a;TaroVue3 搭建适用于微信小程序和 H5 的框架的大致步骤&#xff1a; 安装 Taro。可以在终端输入以下命令进行安装&#xff1a; npm install -g…...

C++:模板初阶(泛型编程、函数模板、类模板)

文章目录1 泛型编程2 函数模板2.1 函数模板概念2.2 函数模板格式2.3 函数模板的原理2.4 函数模板的实例化2.5 模板参数的匹配原则3 类模板3.1 类模板的定义格式3.2 类模板的实例化1 泛型编程 所谓泛型&#xff0c;也就是通用型的意思。 在以往编写代码时&#xff0c;我们常常…...

wordpress snow 3d/凡科建站模板

1&#xff0c;什么是Session Session一般译为会话&#xff0c;是解决Http协议的无状态问题的方案&#xff0c;可以将一次会话中的数据存储在服务器端的内存中&#xff0c;保证在下一次的会话中可以使用。 在客户端浏览器第一次向服务器端发送请求时&#xff0c;服务器端会为这个…...

图片设计 五星级酒店网站/班级优化大师app

对于服务器程序来说&#xff0c;有个基本假设&#xff0c;即服务器是基于状态请求&#xff0c;还是基于无状态请求。根据这个假设&#xff0c;可以将服务器划分为状态服务器和无状态服务器。 状态服务器 如果是状态化请求&#xff0c;那么服务端一般需要保存请求的相关信息&a…...

网站做收录是什么意思/域名权重查询工具

JavaScript之继承什么是继承继承方式属性拷贝原型式继承原型链继承借用构造函数组合继承借用构造函数 深拷贝以下内容转载编辑自LiYajie 什么是继承 js中的继承就是获取存在对象已有属性和方法的一种方式. 继承方式 属性拷贝 就是将对象的成员复制一份给需要继承的对象. …...

wordpress插件启用/福建键seo排名

原标题&#xff1a;python魔鬼训练营本课程主要针对python常用的一些知识点&#xff0c;疑难点进行拆分并单独讲解&#xff1b;每一个课程都会对具体的知识点先进行学习&#xff0c;然后在举一个具体的例子来实践当次课程的内容&#xff1b;使得每一个知识点都可以更加牢固的掌…...

做网站广告哪家好/国内搜索引擎优化的公司

目录 404&#xff1a; &#xff08;1&#xff09;访问资源路径错误&#xff1a; &#xff08;2&#xff09;classes项目输出路径错误&#xff1a; &#xff08;3&#xff09;tomcat没有配置上下文context&#xff1a; 404&#xff1a; &#xff08;1&#xff09;访问资源路径错…...

凡科网多页网站怎样做/大型网站建设平台

H264编码流程手绘图&#xff1a; H264编码网上图&#xff1a; I 帧 Fn&#xff08;左上&#xff09;是当前要编码的帧&#xff0c;他是 GOP 中的第一帧&#xff0c;也就是 I 帧&#xff0c;I 帧要进行帧内编码&#xff0c;首先要选择预测模式&#xff08;Choose Intra predict…...