Visual Studio 2022 你必须知道的实用调试技巧
目录
1、什么是bug?
2.调试是什么?有多重要?
2.1我们是如何写代码的?
2.2又是如何排查出现的问题的呢?
编辑
2.3 调试是什么?
2.4调试的基本步骤
2.5Debug和Release的介绍
3.Windows环境调试介绍
3.1 调试环境的准备
3.2学会快捷键
3.3 调试的时候查看程序当前信息
3.3.1 查看临时变量的值
3.3.2 查看内存信息
3.3.3 查看调用堆栈
3.3.4查看汇编信息
3.3.5 查看寄存器信息
4、多多动手,尝试调试,才能有进步。
5、一些调试的实例
5.1实例一
5.2 实例二
6.如何写出好(易于调试)的代码
6. 1 优秀的代码:
6.2 示范:
7.编程常见的错误
7.1 编译型错误
7.2 链接型错误
7.3 运行时错误
- 🎈个人主页:库库的里昂
- 🎐CSDN新晋作者
- 🎉欢迎 👍点赞✍评论⭐收藏
- ✨收录专栏:编程小白
- 🤝希望作者的文章能对你有所帮助,有不足的地方请在评论区留言指正,大家一起学习交流!🤗
【前言】
大家好,前面我们讲了Visual Studio 2022的安装和使用以及scanf报错的解决方法
今天分享一些实用的 VS 技巧,而这些技巧很多人都不知道。当你以后在工作中遇到:我在同事电脑上解决问题,或在会议上演示代码示例时,使用了一些 VS “骚”操作,他们会好奇地问:你是怎么做到的?有时候你知道一些别人不知道的小技巧便可以让你显得更专业。
PS:本文所有示例演示均基于 Visual Studio 2022 版本。
1、什么是bug?
bug本意是昆⾍”或“⾍⼦”,现在⼀般是指在电脑系统或程序中,隐藏着的⼀些未被发现的缺陷或问 题,简称程序漏洞。
“Bug” 的创始⼈格蕾丝·赫柏(Grace Murray Hopper),她是⼀位为美国海军⼯作的电脑专家, 1947年9⽉9⽇,格蕾丝·赫柏对Harvard Mark II设置好17000个继电器进⾏编程后,技术⼈员正在进⾏ 整机运⾏时,它突然停⽌了⼯作。于是他们爬上去找原因,发现这台巨⼤的计算机内部⼀组继电器的 触点之间有⼀只⻜蛾,这显然是由于⻜蛾受光和热的吸引,⻜到了触点上,然后被⾼电压击死。所以 在报告中,赫柏⽤胶条贴上⻜蛾,并把“bug”来表⽰“⼀个在电脑程序⾥的错误”,“Bug”这个说 法⼀直沿⽤到今天。
2.调试是什么?有多重要?
所有发生的事情都一定有迹可循,如果问心无愧,就不需要掩盖也就没有迹象了,如果问心有愧,就必然需要掩盖,那就一定会有迹象,迹象越多就越容易顺藤而上,这就是推理的途径。
顺着这条途径顺流而下就是犯罪,逆流而上,就是真相。
一名优秀的程序员是一名出色的侦探。
每一次调试都是尝试破案的过程。
2.1我们是如何写代码的?
2.2又是如何排查出现的问题的呢?
拒绝-迷信式调试!!!!
2.3 调试是什么?
调试(debug),又称除错,是发现和减少计算机程序或电子仪器设备中程序错误的一个过程。
2.4调试的基本步骤
- 发现程序错误的存在
- 以隔离、消除等方式对错误进行定位
- 确定错误产生的原因
- 提出纠正错误的解决办法
- 对程序错误予以改正,重新测试
2.5Debug和Release的介绍
Debug 通常称为调试版本,它包含调试信息,并且不作任何优化,便于程序员调试程序。
Release 称为发布版本,它往往是进行了各种优化,使得程序在代码大小和运行速度上都是最优的,以便用户很好地使用。
代码示例:
#include <stdio.h>
int main()
{char *p = "hello world!";printf("%s\n", p);return 0;
}
上述代码在Debug环境的结果展示:
上述代码在Release环境的结果展示:
Debug和Release反汇编展示对比:
所以我们说调试就是在Debug版本的环境中,找代码中潜伏的问题的一个过程。
那编译器进行了哪些优化呢?
请看如下代码:
#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;
}
如果是 debug 模式去编译,程序的结果是死循环。
如果是 release 模式去编译,程序没有死循环。
那他们之间有什么区别呢?
就是因为优化导致的。
变量在内存中开辟的顺序发生了变化,影响到了程序执行的结果。
3.Windows环境调试介绍
注:linux开发环境调试工具是gdb,以后学习了会介绍。
3.1 调试环境的准备
在环境中选择 debug 选项,才能使代码正常调试。
3.2学会快捷键
最常使用的几个快捷键:
F5
启动调试,经常用来直接跳到下一个断点处。
F9
创建断点和取消断点
断点的重要作用,可以在程序的任意位置设置断点。
这样就可以使得程序在想要的位置随意停止执行,继而一步步执行下去。
通常情况下F5和F9是连在一起使用的
假如我们这里有个循环,我想让他在循环5次的时候停下来该怎么办呢?
- 第一步设置断点,然后设置条件
- 第二步按下 F5 程序就可以跳到我们指定的地方了
这里就可以看到我们的程序是走到了第
11
行的,并且运行了5次。因为在监视窗口看到的arr数组是被赋值了5
次的
F10
逐过程,通常用来处理一个过程,一个过程可以是一次函数调用,或者是一条语句。
F11
逐语句,就是每次都执行一条语句,但是这个快捷键可以使我们的执行逻辑进入函数内部(这是最长用的)。
F10
这个快捷键通常是进入函数时使用的也是一个常用快捷键,而 F11
逐语句调试。这个可以进入函数之后搭配使用!
CTRL + F5
开始执行不调试,如果你想让程序直接运行起来而不调试就可以直接使用。
更多快捷键点这里!
3.3 调试的时候查看程序当前信息
3.3.1 查看临时变量的值
在调试开始之后,用于观察变量的值。
3.3.2 查看内存信息
3.3.3 查看调用堆栈
通过调用堆栈,可以清晰的反应函数的调用关系以及当前调用所处的位置。
3.3.4查看汇编信息
在调试开始之后,有两种方式转到汇编:
(1)第一种方式:右击鼠标,选择【转到反汇编】:
(2)第二种方式:
可以切换到汇编代码。
3.3.5 查看寄存器信息
可以查看当前运行环境的寄存器的使用信息。
4、多多动手,尝试调试,才能有进步。
- 一定要熟练掌握调试技巧。
- 初学者可能80%的时间在写代码,20%的时间在调试。但是一个程序员可能20%的时间在写
- 程序,但是80%的时间在调试。
- 我们所讲的都是一些简单的调试。
- 以后可能会出现很复杂调试场景:多线程程序的调试等。
- 多多使用快捷键,提升效率。
5、一些调试的实例
5.1实例一
实现代码:求 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
代码结果:
实际输出的是15。
why?
这里我们就得找我们问题。
- 首先推测问题出现的原因。初步确定问题可能的原因最好。
- 实际上手调试很有必要。
- 调试的时候我们心里有数。
首先我们可以确定是结果出现的问题,而结果又是循环来计算,我们就可以进去循环然后把监视窗口调开看看是不是这里的问题?
- 3的阶乘应该是 (1*1)+(1*2)+(1*2*3) =9
这里我们通过调试就可以看到,我们的循环在第三次的时候就出现错误了。本来 ret
里面存储的是 3
的阶乘 9
可结果却是 12
- 这里可以得出我们程序的错误了
ret
这个变量未初始化导致结果与预想不同
代码改进:
5.2 实例二
#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;
}
代码结果:
代码死循环,研究程序死循环的原因。
深度解析为什么会死循环
这时就要用到我们调试里面的内存功能了,其实这里 笔试题
为什么死循环的原因很简单,我们前面说过临时变量是存在 栈区
的,而 栈区
的使用习惯是;
- 先使用高地址的空间在使用地地址的空间
- 所以变量
i
就在数组上面一点创建的 - 那么我们就可以画这样一幅图
观察内存
我们这里就可以调试一下,观察临时变量 i 和临时变量 arr 是不是在栈区是这样存储的!
这里为了观察方便就把数组初始化的时候先放上值!
- 取地址 i 得到的地址是 0x00A6FBC0
- 取地址arr 得到的地址是 0x00A6FBF0
这里就可以看到我们临时变量 arr
和 i
在内存 栈区中地区是这样存储的!当我们循环第13次时 arr[13]
越界!
- 就会找到我们临时变量
i
的地址值处从而 - 改为
0
开始无限循环
总结:所以我们在使用数组时一定要注意数组越界这个问题,不然就会引发bug。
6.如何写出好(易于调试)的代码
6. 1 优秀的代码:
- 代码运行正常
- bug很少
- 效率高
- 可读性高
- 可维护性高
- 注释清晰
- 文档齐全
常见的coding技巧:
- 使用assert
- 尽量使用const
- 养成良好的编码风格
- 添加必要的注释
- 避免编码的陷阱。
6.2 示范:
模拟实现库函数: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 );
}
注意:
- 分析参数的设计(命名,类型),返回值类型的设计
- 这里讲解野指针,空指针的危害。
- assert的使用,这里介绍assert的作用
- 参数部分 const 的使用,这里讲解const修饰指针的作用
- 注释的添加
3.3const的作用:
#include <stdio.h>
//代码1
void test1()
{int n = 10;int m = 20;int* p = &n;*p = 20;//ok?p = &m; //ok?
}
void test2()
{//代码2int n = 10;int m = 20;const int* p = &n;*p = 20;//ok?p = &m; //ok?
}
void test3()
{int n = 10;int m = 20;int* const p = &n;*p = 20; //ok?p = &m; //ok?
}
int main()
{//测试无cosnt的test1();//测试const放在*的左边test2();//测试const放在*的右边test3();return 0;
}
结论:
const修饰指针变量的时候:
1. const如果放在*的左边,修饰的是指针指向的内容,保证指针指向的内容不能通过指针来改变。但是指针变量本身的内容可变。
2. const如果放在*的右边,修饰的是指针变量本身,保证了指针变量的内容不能修改,但是指针指向的内容,可以通过指针改变
const的具体介绍会在之后发布文章
7.编程常见的错误
7.1 编译型错误
直接看错误提示信息(双击),解决问题。或者凭借经验就可以搞定。相对来说简单。
7.2 链接型错误
看错误提示信息,主要在代码中找到错误信息中的标识符,然后定位问题所在。一般是标识符名不存在或者拼写错误。
7.3 运行时错误
借助调试,逐步定位问题。最难搞。
温馨提示:
做一个有心人,积累排错经验。
讲解重点:
介绍每种错误怎么产生,出现之后如何解决。
Visual Studio 2022 你必须知道的实用调试技巧到这里就讲完了,后续我会发布一些其他知识,大家可以订阅一下专栏呀!
相关文章:
Visual Studio 2022 你必须知道的实用调试技巧
目录 1、什么是bug? 2.调试是什么?有多重要? 2.1我们是如何写代码的? 2.2又是如何排查出现的问题的呢? 编辑 2.3 调试是什么? 2.4调试的基本步骤 2.5Debug和Release的介绍 3.Windows环境调试介绍…...
Webgl 存储限定符attribute、gl.getAttribLocation、gl.vertexAttrib3f及其同族函数和矢量版本的介绍
目录 attribute变量规范 获取attribute变量的存储位置 gl.getAttribLocation()函数的规范: 向attribute变量赋值 gl.vertexAttrib3f()的规范。 gl.vertexAttrib3f()的同族函数 示例代码…...
postgresql跨库创建视图
需求: A库a表中的字段拆分1个到B库b表,所以b表中只保留唯一标识字段(可以理解为id)和另一个被拆分的字段 需要用到的拓展:CREATE EXTENSION dblink 使用dblink创建连接: SELECT dblink_connect(other_db, hostaddr【IP…...
FPGA时钟
几年前FPGA时钟只需要连接一个单端输入的晶振,非常容易。现在不同了,差分时钟输入,差分信号又分为LVDS和LVPECL,时钟芯片输出后还要经过直流或交流耦合才能接入FPGA,有点晕了,今天仔细研究一下。 FPGA输入…...
FifthOne:计算机视觉提示和技巧
一、说明 欢迎来到我们每周的FiftyOne提示和技巧博客,我们回顾了最近在Slack,GitHub,Stack Overflow和Reddit上弹出的问题和答案。FiftyOne是一个开源机器学习工具集,使数据科学团队能够通过帮助他们策划高质量数据集、评估模型、…...
Oracle19c-补丁升级报错合集(一)
前言: 本文主要介绍Oracle19c补丁升级遇到的问题,涉及安装补丁prepatch步骤,apply应用报错以及datapatch -verbose数据字典更新报错 问题一: 在执行补丁rootcrs.sh -prepatch操作时,发生执行检查命令cluutil -chkshare报错 CLSRSC-180: An …...
嵌入式:ARM Day6
作业:完成cortex-A7核UART总线实验 目的:1.输入a,显示b,将输入的字符的ASCII码下一位字符输出 2.原样输出输入的字符串 源码: uart4.h #ifndef __UART4_H__ #define __UART4_H__#include "stm32mp1xx_rcc.h" #incl…...
ClickHouse安装步骤
文章目录 ClickHouse安装步骤背景安装启动用户相关修改密码登录验证新增用户config配置文件 基本操作服务管理 ClickHouse安装步骤 背景 经过研究ClickHouse是列式数据库,下面是在Centos7.9版本单机版的安装的演示 安装 首先安装yum-utils工具包 sudo yum inst…...
Android CCodec (二十) CCodec Native服务实现分析
1、C2解码服务registerAsService注册流程 google实现CCodec的vendor默认解码服务代码路径是在frameworks/av/media/codec2/hidl/services/vendor.cpp中,而其注册的是HIDL服务,本文就对HIDL服务注册做简要分析。首先看下vendor.cpp中的代码注册流程。 int main(int /* argc *…...
Shell编程学习之while循环语句和for循环语句的应用
Shell编程中的while循环:可以类比C语言中的while循环进行学习,详见本人原创博客链接: https://blog.csdn.net/qq_41878292/article/details/132081302?spm1001.2014.3001.5502伪代码表示: while 表达式 do循环体 done用法类比S…...
【校招VIP】CSS校招考点之选择器优先级
考点介绍: 选择器是CSS的基础,也是校招中的高频考点,特别是复合选择器的执行优先级,同时也是实战中样式不生效的跟踪依据。 因为选择器的种类较多,很难直接记忆,可以考虑选择一个相对值,比如id类…...
Netty+springboot开发即时通讯系统笔记(四)终
实时性 1.线程池多线程,把消息同步给其他端和对方用户,其中数据持久化往往是最浪费时间的操作,可以使用mq异步存储,因为其他业务不需要拿着整条数据,只需要这条数据的id进行操作。 2。消息校验前置,放在t…...
java -jar 启动服务后,关闭命令窗口后服务停止
java -jar 启动服务后,关闭命令窗口后服务停止 问题:当我们用java -jar命令启动服务后,只有一直保持Xshell的窗口开启且正常连接服务器时才能访问服务,当关闭命令窗口时,服务会停止运行 解决:使用nohup命…...
Android PowerManager的使用
唤醒锁定 如果需要使 CPU 保持运行状态,以便在设备进入休眠模式之前完成某项工作,可以使用“唤醒锁定” 。 添加权限 <uses-permission android:name"android.permission.WAKE_LOCK" />设置唤醒锁定 PowerManager powerManager (Po…...
安防监控/视频集中存储/云存储平台EasyCVR v3.3增加首页告警类型
安防监控/视频集中存储/云存储EasyCVR视频汇聚平台,可支持海量视频的轻量化接入与汇聚管理。平台能提供视频存储磁盘阵列、视频监控直播、视频轮播、视频录像、云存储、回放与检索、智能告警、服务器集群、语音对讲、云台控制、电子地图、平台级联、H.265自动转码等…...
7-6 统计字符出现次数
分数 20 全屏浏览题目 切换布局 作者 C课程组 单位 浙江大学 本题要求编写程序,统计并输出某给定字符在给定字符串中出现的次数。 输入格式: 输入第一行给出一个以回车结束的字符串(少于80个字符);第二行输入一个…...
美国大模型风向速报(一)为何重视提示工程?LangChain+向量数据库+开源大模型真香...
多家,且独家来自美国的信源同时向“亲爱的数据”表示, 提示工程(Prompt Engineering)在美国大模型领域备受重视。 读者都要聊, 那就干活。 (一)开源真香 现阶段,AI开源极客大展身手&…...
excel统计函数篇2之count系列
1、COUNT(value1,[value2],…):计算参数列表中数字的个数 2、COUNTA(value1,[value2],…):计算参数列表中值的个数 联想在excel之数学函数、excel中的通配符一文中提到求和函数: SUMIF(range,ceriteria,[sum_range]):对范围内符合指定条件的…...
vue3组件多个根节点报错
打开扩展商店搜索下载 vetur 打开设置命令面板 搜索eslint 将下面的勾选取消...
基于Rust的QuickLZ压缩算法的详细实现与分析
1. 引言 QuickLZ是一种被广泛应用的高效压缩算法。在许多应用中,快速的数据压缩和解压缩是非常关键的,特别是在网络传输和存储空间有限的场景中。为了满足现代软件开发的需求,我们将使用Rust语言来实现这一算法。Rust是一种专为系统级编程而…...
next.js 创建 react ant design ts 项目
环境说明:next.js 官方文档要求node版本在16.8以上。笔者使用的 node版本是16.20.1,不要使用16.13.0,笔者在使用 node16.13.0环境时创建的 react 项目点击事件无效 next.js官网截图 next.js 官网:https://nextjs.org/ react 官网…...
无涯教程-Perl - use函数
描述 此函数将MODULE导出的所有功能(或仅LIST引用的功能)导入当前包的名称空间。有效等效于- BEGIN { require "Module.pm"; Module->import(); }也用于在当前脚本上强加编译器指令(编译指示),尽管从本质上讲它们只是模块。 请注意,use语句在编译时进行判断。在…...
(7)(7.6) 恢复任务回放
文章目录 前言 7.6.1 配置 7.6.2 工作原理 7.6.3 局限性 前言 本页介绍了什么是"任务继续时后退"功能以及如何使用该功能。 !Note 从 4.1 版起,Plane、Copter 和 Rover 均可使用此功能。 在某些应用或运行区域,为了消除冲突&…...
spark yarn 开启动态资源分配
概念 不需要指定并发,只需要指定内存, 程序在运行后会动态调节并发数量,我们只需要设置一个上线即可 在spark 配置文件设置: spark.dynamicAllocation.enabled true spark.shuffle.service.enabled true 准备shuffer jar 将spar…...
Android学习之路(8) Activity
本节引言: 本节开始讲解Android的四大组件之一的Activity(活动),先来看下官方对于Activity的介绍: 移动应用体验与桌面体验的不同之处在于,用户与应用的互动并不总是在同一位置开始,而是经常以不确定的方式开始。例如&…...
Linux的热拔插UDEV机制
文章目录 UDEV简介守护进程基本特点 守护进程和后台进程的区别开发守护进程结束 UDEV简介 udev是一个设备管理工具,udev以守护进程的形式运行,通过侦听内核发出来的uevent来管理/dev目录下的设备文件。 udev在用户空间运行,而不在内核空间 …...
Azure应用程序网关
文章目录 什么是应用程序网关实战演练创建虚拟网络创建虚拟机创建应用程序网关测试搭建结果 什么是应用程序网关 Azure应用程序网关是一种托管服务,用于提供安全、可缩放的 Web 应用程序前端点的应用程序传送控制和保护。它可以通过 SSL 终止、cookie 基于会话持久…...
免费开源服务器资源监控系统grafana+prometheus+node_exporter
有项目做测试的时候需要查询服务器资源利用情况,自己又没写相应的模块,此时就需要一套好用的资源监控系统,,咨询了运维人员给推荐了一套,装完后真的很好用。 就是grafanaprometheusnode_exporter(linux&am…...
【文化课学习笔记】【化学】金属及其化合物
【化学】必修一:金属及其化合物 钠及其化合物 钠单质 物理性质 颜色:银白色,有金属光泽;密度: ρ H 2 O > ρ N a > ρ 煤油 \mathrm{\rho_{H_2O}>\rho_{Na}>\rho_{煤油}} ρH2O>ρNa>ρ煤…...
Java面试题--设计模式
一、Java 中有几种设计模式? Java 中一般认为有 23 种设计模式 分为三大类: 1. 创建型模式 5 种 ① 工厂方法模式 ② 抽象工厂模式 ③ 单例模式 ④ 建造者模式 ⑤ 原型模式 2. 结构型模式 7 种 ① 适配器模式 ② 装饰器模式 ③ 代理模式 ④ 外观模式 …...
做视频网站都需要什么/任务推广引流平台
上一篇文章我们分析了sharding-jdbc 的路由(路由),今天我们分析下sql改写。 闲聊:翻了Sharding-Sphere 的文档,也对SQL【解析、路由、改写、执行、归并】引擎做了介绍,大家有兴趣可以看看。 主要类: SQLRew…...
建筑工程网签合同周末可以签吗/seo是什么
本文已迁移至:https://blog.csdn.net/COCO56/article/details/89382093 原标题:VS各版本下载与密钥(从2008到2017),VS老版本在官网如何下载(解决下载老版本时提示抱歉,我们找不到适合您的下载内容的问题&a…...
java+做网站后台/武汉关键词排名工具
众所周知,swap就是交换分区的意思。 但是什么是交换分区,你真的知道吗? SWAP就是LINUX下的虚拟内存分区, 它的作用是在物理内存使用完之后,将磁盘空间(也就是SWAP分区)虚拟成内存来使用. 它和Windows系统的交换文件作用类似,…...
免费设计房屋的网站/淘宝关键词top排行榜
(1) 十进制转换为二进制,分为整数部分和小数部分① 整数部分方法:除2取余法,即每次将整数部分除以2,余数为该位权上的数,而商继续除以2,余数又为上一个位权上的数,这个步骤一直持续下去…...
网络诈骗做网站 维护/seo教程网站优化推广排名
讲述一下自己的分支合并到 dev 分支的过程;比如自己的分支叫:feature/v1.1-historydata 1.在自己的分支 先 git add . 把修改的代码存到暂存区里面去,然后 git commit -m 提交的提示信息,这个代码的作用是把暂存区的修改好的代码提…...
北京网站建设app/国外域名注册平台
内容来源于悟空问答"如何看待程序员在火车站候车室写代码画面曝光?"作者:大学生编程指南原文可点击阅读全文前去围观。10月2日,有网友曝光了某程序员在火车站候车室写代码的画面,网友评价这是程序员的悲哀。大过节的,许…...