Visual Studio 的调试(一)

最近事儿很多昂,更新速度相较以往慢了许多,备考六月份的四级,还有学校的期末等等,事儿真的太多啦,所以后面的更新速度也会放慢一点,实在是抽不开身啊诸位,相当抱歉,还望诸君见谅

言归正传,咱们今天来聊一聊有关VS的调试技巧。调试是相当重要的一点,熟练地运用调试可以帮助我们自身检验代码的可行性,并快速地找出问题所在

一 . Bug

不知道大家第一次认识bug是什么时候昂,我第一次听到这个词还是在小学看陈子豪打CF说的,这也算是他的一个口头禅吧,当时我就只知道bug就是一种类似程序意料之外的漏洞的意思

什么是bug呢?其英文的本意是指" 虫子 "," 昆虫 ",而在现在的网络中逐渐被演变成了在我们的电脑系统或程序中,隐藏着一些未被发现的问题,也就是" 缺陷 "," 漏洞 "的意思

那么这个时候就有小伙伴要问了,这一演变从何而来呢?Good question!查资料可得:
"Bug" 的创始人是 格蕾丝·赫柏 (Grace Murray Hopper),她是一位为美国海军工作的电脑专家,在1947年9月9日,格蕾丝·赫柏对 Harvard Mark II设置好17000个继电器进行编程后,技术人员正在进行整机运行时,它突然停止了工作。于是他们爬上去找原因,发现这台巨⼤的计算机内部⼀组继电器的触点之间有一只飞蛾,这显然是由于飞蛾受光和热的吸引,飞到了触点上,然后被高电压击死。所以在报告中,赫柏用胶条贴上飞蛾,并把 " bug "来表示" 一个在电脑程序里的错误 " ,从此以后," Bug "这个说法就一直沿用至今

历史上的第一个" bug "(图源网络)

二 . Debug 和 Release

Debug就是我们常说的调试,顾名思义调试也就是我们找程序漏洞的一个过程,Debug也就是消灭bug的意思。大家调试一个程序,我们首先是要承认出现了问题,然后我们通过一些手段去定位到问题,可以是逐过程的调试,也可以是隔离和屏蔽代码的方式,当我们找到问题的所在,再确定了问题产生的原因,我们就可以去修复代码了

之前我们就有提到过,在VS中,我们可以选择不同的编译环境,如:Debug 和 Release


Debug 称为调试版本 :它 包含调试信息,并且不作任何优化 ,便于程序员调试程序; 程序员在写代码的时候,需要经常性的调试代码,就将这里设置为 debug ,这样编译产生的是debug 版本的可执行程序,其中包含调试信息,是可以直接调试的
Release 称为发布版本 :它往往是 进行了各种优化,使得程序在代码大小和运行速度上都是最优的 ,以便用户很好地使用。当程序员写完代码,测试员再对程序进行测试,直到程序的质量符合交付给用户使用的标准,这个时候就会设置为 release ,编译产生的就是 release 版本 的可执行程序, 这个版本是用户使用的,所以无需包含调试信息等 (如果大家感兴趣的话,可以试着将一个文件分别用 Debug 和 Release保存,我们会发现 Debug版本的所占内存会大一些,这就是因为Debug版本包含了调试信息等

三 . VS的调试快捷键

在VS中有着各式各样的快捷键,我这里给大家列举几个常用的、有代表性的:
F10:逐过程,通常用来处理一个过程,一个过程可以是一次函数调用,或者是一条语句
F11:逐语句,就是每次都执行一条语句,但是这个快捷键可以使我们的执行逻辑进入函数内部
在函数调用的地方,想进入函数观察细节,必须使用F11,如果使用F10,直接完成函数调用
F9:创建断点和取消断点
断点的作用 :可以在程序的任意位置设置断点,打上断点就可以使得程序执行到想要的位置暂停执执行,接下来我们就可以使用F10,F11这些快捷键,观察代码的执行细节
条件断点 :满足这个条件,才触发断点
F5:启动调试,经常用来直接跳到下一个断点处,一般是和F9配合使用
CTRL + F5:开始执行不调试,如果你想让程序直接运行起来而不调试就可以直接使用
(一般我们运行代码都用这个快捷键)
VS更多快捷键了解:http://blog.csdn.net/mrlisky/article/details/72622009

四 . 监视和内存观察

在我们开始调试后,在菜单栏中,调试------>窗口------>监视,我们任意打开一个监视窗口,输入我们想要监视的对象,如:

在监视窗口中观察各项数据:

我们按F10,输入想要监视的对象,然后我们再按一次F10,即可进行到下一条语句,以此类推,直到程序结束跳出

若是大家觉得我们在监视窗口中观察的还不够细致时,我们可以进入内存中去观察变量在内存中的储存情况,如:

在我们的内存窗口中就可以观察到:

在这里的自动的选项我们可以设置一行显示几列(我们一般会设置为4列):


除此之外,在我们的调试的窗口中还有:自动窗口,局部变量,反汇编、寄存器等窗口,我这里就不一 一为大家赘述, 诸君感兴趣的话可以自行去搜集影视资料学习。

五 . 有关调试的举例

为了让大家加深对调试概念的理解,咱们在这里用一个经典例题练练手:

大家可以试着想想运行结果是什么?

这个程序运行起来很显然是会死循环的,这一点相信诸君都能看得出来,这题的关键是我们怎么去理解它为什么死循环,用官方的话术解释清楚问题的根本

当我们调试运行到第十个 hehe 的时候还一切正常,但当我们继续的时候,程序可以无休止的打印hehe,大家自己去运行可以发现,最下面的光标是在一直闪烁的,这就证明程序一直在进行,在无休止的打印,像这样:

这个时候就有小伙伴要问了,这也没有报错啊,代码怎么就有问题了呢?

大家要注意,这个代码肯定是错误的,我们数组arr中只能存10个整型,也就是说,当我们 i 变成10的时候,就已经越界访问了,再向后越界访问,我们就有可能覆盖到 i 的地址,从而导致程序的死循环。至于为什么没有报错呢?那是因为程序死循环了嘛,它一直忙着打印 hehe 呢,吃了炫迈一样,根本停不下来,所以来不及报错

此题其内存布局如图:

(1)栈区内存的使用习惯是从高地址向低地址使用的,所以变量i的地址是较大的,及arr数组的地址整体是小于 i 的地址

注意:在VS上切换到X64版本,这个使用的顺序是相反的,在Release版本的程序中,这个使用的顺序也是相反

(2)数组在内存中的存放是:随着下标的增长,地址是由低到高变化

由此可见,在此题中, 随着数组下标的增长,往后越界就有可能覆盖到 i 的地址 ,这样就可能造成死循环

这里可能有小伙伴要问了:为什么 i 和 arr 数组之间恰好空出来2个整型的空间呢?这里确实是巧合,在不同的编译器下可能中间的空出的空间大小是不一样的,代码中这些变量内存的分配和地址分配是编译器指定的,所以的不同的编译器之间就有差异了,这也就是为什么题目在一开始就会告诉我们是在Debug 、x86环境下进行
这个理解我们就能够清楚的体会到调试的重要性,只有调试才能观察到程序内部执行的细节,就像医生给病人做B超,CT一样
总结:调试是需要反复去动手练习的,诸君一定要自己动手多调试,从中汲取经验。调试是可以增加程序员对代码的理解和掌控的,掌握了调试的能力,就能看到本质,对程序内部一览无余。熟练的掌握调试技巧是一个优秀的程序员的必备技能

OKK,有关VS中调试的相关知识就给大家聊到这里了。 程序运行时的错误,是千变万化的,这个时候我们可以借助调试,去逐步定位每条语句的问题,调试观察并解决我们程序在运行时出现的问题。当然了,这肯定不是一日之功嘛,而是一个日积月累的过程,无他唯手熟尔。无需多言,诸君记得勤练手,咱们共勉!!!下期再见,886!

相关推荐
Kisorge12 小时前
【C语言】代码BUG排查方式
c语言·开发语言·bug
安卓机器17 小时前
探索 Python编程 调试案例:配置日志记录器查看程序运行bug
bug
树懒_Zz3 天前
记录 io.springfox 3.0.0 整合 spring boot 2.6.x 由于 springfox bug 引发问题
windows·spring boot·bug
每天进步一大步3 天前
webSokect安卓和web适配的Bug 适用实时语音场景
android·前端·bug·web
JWASX3 天前
【BUG记录】Apifox 参数传入 + 号变成空格的 BUG
java·bug·urlencoder·urldecoder
初遇你时动了情3 天前
解决react 路由切换,页面闪屏的bug
javascript·react.js·bug
老赵的博客3 天前
QString转const char* bug
bug
andlbds4 天前
解决PCL库中pcl::VoxelGrid降采样Bug
c++·bug
乌漆嘎嘎黑4 天前
XIO: fatal IO error 22 (Invalid argument) on X server “localhost:10.0“【小白找bug】
pytorch·python·bug·matplotlib·mobaxterm
curd_boy6 天前
【BUG】记一次context canceled的报错
golang·bug