【教程】visual studio debug 技巧总结

2023-05-16

更新中 …
基础的调试技巧基本更新完毕,visual studio 提供了强大的调试功能,许多东西需要大家动手体验

目录

  • 环境
  • 调试器的基本使用
    • 更改执行流
    • 断点
      • 基本的断点操作
      • 跟踪点
      • 条件断点
        • 条件表达式
        • 命中次数
        • 过滤器
    • 函数断点
      • 缩小函数范围
    • 数据断点
    • 断点管理
    • 各种窗口
      • Error List 窗口
      • Autos 和 Local 窗口
      • 监视窗口
      • 函数调用堆栈
  • 调试运行中的程序
  • _DEBUG 宏与 debug 模式
  • 其它技巧
    • 快速重启 debug
    • 固定,值的位置
    • 获取变量的内存地址
    • 调试时变量值的进制转换
  • 其他
    • 烫烫烫与屯屯屯
  • 参考

环境

  1. 操作系统:Windows 10
  2. IDE:Visual studio 2017
    【注】不同版本的 Visual studio 可能会有细微的差别

调试器的基本使用

更改执行流

当调试执行到 21 行时,想要回到前面的行,只需要抓住黄色箭头拖动其回到前面的行(如 18 行)即可从那里开始执行
在这里插入图片描述

断点

当我们需要在代码执行的过程中,从某条语句开始,停下来一步一步,一条一条地过每一条代码的时候,这是我们就需要用到断点。

基本的断点操作

  1. 设置基本断点
    在这里插入图片描述

如上图,在你需要停下来的语句中,在其左侧的那条竖栏处左击,就会出现一个红色圆点,这表示当你运行代码的时候(不是运行 .exe 程序)会在这里停下来。

【注】程序只会从断点开始的地方停下来,而之前的语句将会快速执行过去。

  1. 进入调试
    在这里插入图片描述

按上图红框所示,进入调试状态。

  1. 调试界面简述
    在这里插入图片描述

在调试程序启动后,程序快速运行至 ① 处停下等候你的下一步操作,可以看见,红色的 ① 上面多了一个黄色的向右箭头,这表示当前程序运行到了这条语句。

② 处有三个操作符:
向下的箭头表示,进入更深层次的代码中。比如,当黄色箭头运行到一个调用的函数时,我想进入看看这个函数内部究竟是怎么运行的,就可以用这个箭头。

弯曲向下的箭头表示在当前程序中一条一条执行。那上一个箭头中的例子举例,我并不想进入这个调用的函数,仅仅想在当前页面执行函数,就用这个箭头。

向上的箭头,表示跳出更深层次的代码。还是那最开始的例子举例,如果你进入了更深层次的函数中,但这个函数太冗长了,你想跳出来,回到本来执行的页面,就应该用这个箭头。

③ 处有一个红色的方框,这表示停止调试,退出调试。

④ 处,可以看到下面有两个输出数据的框。如果你仔细观察,这些框的底部还有一排隐藏的框,比如 Autos 的右边还有 Locals,Watch1 这些隐藏起来的框。这些输出框可以帮助你进行调试。

  1. 【补】快速执行到某行代码
    我们对上面的代码进行了微调,新增了几条语句用于演示这个功能。
    在这里插入图片描述
    在上图中,我们调试代码,程序运行到断点处停止,但是我觉得循环太久了,想跳到下面的第三条 i++ 语句处,那么我们可以直接把光标移动到 i++ 上,然后它的左边会出现一个绿色的向右箭头(如图中所示),当我们点击这个箭头,就可以快速执行到这个语句,并且它之前的代码也会执行到。
  2. 快速从上一个断点执行到下一个断点:具体的做法是按 F5。在下图中,我设置了两个断点,分别在第七行和第二十五行,在两个断点之间有一些变量和一个循环 100 的循环体。

设我们从第七行开始执行,如果按 F5,则程序直接执行到第二十五行,而不是像单步调试一样一步步前进。注意,即使你从第七行开始进行单步调试,也可以通过 F5快速执行到第二十五行。
在这里插入图片描述

跟踪点

跟踪点的作用是可以在 Output 窗口中打印出你设置的一些信息。
在这里插入图片描述
在这里插入图片描述
我们来举一个例子,还是之前的代码,我们将断点打在 cout << "当前的 i 值: " << i << endl; 上,我想在 Output 窗口输出一些打印的信息。

将鼠标放在断点处,弹出的小框中选择齿轮在这里插入图片描述样式。点击后就可以进行设置。
在这里插入图片描述
在上图中,通过 Actions 中的输入框,可以输入你想打印的信息。这里我想输出变量 i 的数据,于是用 {} 包裹住 i

勾选 Continue execution 表示不将跟踪点视为断点,也就是程序在调试时不会在此停顿。

下面我来看看效果,Output 输入框中打印出了我们想要的信息。
在这里插入图片描述
这里有更多的特定信息
在这里插入图片描述

条件断点

所谓条件断点,是断点处,当满足了你设置的条件时才会触发。一般可以和跟踪点搭配使用。
在这里插入图片描述
继续沿用之前的代码,在上图中,我们可以看到大的红色框包含了条件断点的三种类型,分别是条件表达式,命中次数和过滤器,下面我们一个一个来讲。

条件表达式

条件表达式是指满足了给定的条件表达式,断点或者跟踪断点才会被触发。
在这里插入图片描述
如上图,设置 i%2 == 0,表示当该断点处,该条件为真(is true)时,跟踪断点才会被触发,记录相应的输出信息。

效果如下,Output 框中确实只输出了偶数次的记录。
在这里插入图片描述
下面再举一个对普通断点设置条件的例子。
如图,当 i 循环到 5 的时候,该断点会被触发。
在这里插入图片描述
具体怎么设置见下图:鼠标移动到普通的断点上,然后选择齿轮图标即可进入上图的状态,设置即可。
在这里插入图片描述

命中次数

如图,当命中次数 >= 5 时,断点或者跟踪断点被触发执行。
在这里插入图片描述
如上图,我们设定当此处的断点被执行了 5 次后触发。

过滤器

过滤器用于显示指定的输出信息,在这里不详述,因为我也没用过这个功能,大家有兴趣的,可以通过参考部分的链接进行学习。

函数断点

函数断点用于专门进行调用函数时的中断操作,适合只知道函数名字不知道函数位置,或者中断多个重名函数(重载函数)等。

具体操作如下
在这里插入图片描述
在输入框中输入函数的名字
在这里插入图片描述
我们再次进行调试的时候,它就会自动将断点打在 FuncA 的位置
在这里插入图片描述

缩小函数范围

诸如有时候函数会出现重载的问题,输入一个函数名会中断所有的同名函数,那么要缩小范围,可以书写更详细的函数细节,如存在重载的函数 Func(),我只想中断其中形参为 intstring 的函数,则输入 Func(int, string); 为限定

数据断点

数据断点用于变量值发生更改的时候中断执行,如果未发生更改,则执行不会中断。这里讲一种便捷的方式,具体做法如下:
首先,我们要进入调试状态,然后选择要操作的变量,通过 Add Watch 将其添加到 Watch 窗口
在这里插入图片描述
当代码第一次执行到变量的时候将其添加数据断点
在这里插入图片描述
当执行到变量值发生改变的时候,就会产生提示
在这里插入图片描述

断点管理

大型的项目里,在调试的时候,往往有许多的断点,如何管理这些断点如何知道这些断点在什么位置呢?通过 【Debug】-【Windows】-【BreakPoints】或快捷键 ctrl + alt + B 可以查看整个 solution 中的断点。
在这里插入图片描述

各种窗口

最开始我们讲到了,在代码区域的下方,有各种各样的窗口,这些窗口具有不同的功能,用来辅助我们进行 debug,输出响应的信息。

Error List 窗口

error list 窗口可以说是在调试的时候使用频率非常多的窗口了,当你在 build(构建)时,如果程序有编译或链接的错误,都会在这里体现出来,下面我们来举一个例子。

在下图中,我通过一段示例代码,使得程序在 build 的时候报出了一个错误(虽然显示的是 2 Errors,但实际是同一个问题),这是一个非常典型的不能解析外部符号引用的错误
在这里插入图片描述
关于本例是如何造成这个错误的,在这里不阐述,只是通过这个错误看一下 Error List 提供了哪些功能。

在主要的窗格部分,从左至右以此排列的是

  1. Code:这里显示的是错误的类型,如图中是 LNK2019LNK1120,LNK 是 link 的缩写,表示是一个链接阶段的错误,20191120 是错误的类型,注意,这两个都是可以点击的超链接,比如点击 LNK2019 会跳转到 MSDN 提供的关于解释该错误原因的网页,方便用户进行调试
    在这里插入图片描述
  2. Description:提供了关于当前错误的描述
  3. Project:展示了当前错误所在的 Project(项目),当你的 Solution 有多个 Project 时,可以让你定位错误来源
  4. File:即错误具体产生的文件,如上图是在 main.obj 文件中产生的错误,main.objmain.cpp 经过编译,汇编后产生的目标对象文件
  5. Line:显而易见表示行数

Autos 和 Local 窗口

  1. 在 C++ 中,Autos 窗口显示前三个代码行中的变量
    在这里插入图片描述
  2. 显示函数返回值:Autos 窗口也会自动显示当前执行流作用域中,已经执行的函数的返回值。若某作用域中有多个子函数,每个子函数都执行完毕,Autos 仅显示最新执行完的函数的返回值
    在这里插入图片描述
    Locals 窗口显示当前作用域范围中的变量。

监视窗口

在这里插入图片描述
将变量加入到监视窗口,你可以通过该窗口持续关注变量的变化。当超出该变量的范围时,监视窗口的变量变灰。
在这里插入图片描述

函数调用堆栈

在这里插入图片描述
函数调用堆栈可以很方便的让我们在调试时定位当前执行函数的位置,尤其是项目中出现了异常或者错误,而且异常错误是在引入的 DLL 中,这就可以用于定位错误的位置。

如图上图所示的代码中,main,FuncA,FuncB 是以此嵌套的关系,在 main 中调用 FuncA 处设置断点,以此进入调用函数,可以看到函数的调用关系。

除了 Call Stack 可以查看函数调用栈外,Stack Frame 也有相同的作用,一般开发中,Stack Frame 我使用的更多,因为它是固定在工具栏中的
在这里插入图片描述

调试运行中的程序

很多时候,我们需要调试一个已经 build 好的 .exe 的程序(一个运行的进程),这时我们就需要使用 vs 提供的 attach 的功能。具体步骤如下:

  1. 在 Debug 选项中,选择 Attach to Process
    在这里插入图片描述
  2. 在弹出的对话框中,在红色框区域选择你想要调试的 exe 程序即可
    在这里插入图片描述
    下面介绍一下这个对话框里面的内容,在不同情况下,你需要选择不同的调试方式。
  • Connection type:一般来说你只需要选择 Default 选项即可(即本地调试),如果需要远程调试别的计算机上的进程,则需要选择 Remote,关于这种调试方式超出了本文想要撰写的范围,你可以自行去了解
  • Available porcesses:在这里选择你要调试的进程,要快速找到你想要的进程,先选中一个进程,然后直接键入你要的进程的名字即可
  • Attach to:
    - Automatically determine the type of code to debug:自动选择调试的类型
    - Debug these code types:提供了大量调试的类型,你可以根据自己的需要进行选择。一般来说,C/C++ 的调试选择 Native 选项
    【注】想要快速重新 attach 一个之前 attach 的进程,可以使用 Reattach to Process 这个选项,它位于该小节第一幅图红框的下一个选项

_DEBUG 宏与 debug 模式

在编写代码的时候,一开始,我们都是在 debug 模式下编写,这时我们会为了打印一些信息而在代码中编写输出函数,但是当放到 release 模式下时,我们肯定不能把这些输出信息给打印出来,但一方面有时这些 debug 模式下的打印信息很多,很分散,另一方面,有时需要不停在 debug 和 release 下来回切换,这就使得单纯的增加和删除输出语句很麻烦。幸好,C++ 提供了 DEBUG 宏的方式,结合条件编译语句,可以让这些打印语句只在 debug 模式下起作用。

// 在 debug 模式下执行这条语句
#ifdef _DEBUG
	cout << "调试模式" << endl;
#else
	cout << "生产模式" << endl; // 这条代码是作为对比,在实际开发过程中,当然可以不要这段代码
#endif

当然,上面的代码还可以得到进一步的优化使得更加简便,具体可以阅读我在“参考”部分给出的链接8,9。

其它技巧

快速重启 debug

在这里插入图片描述
红色框圈起的是重启调试按钮,如果你在调试的时候修改了代码,或者想要重新执行调试,那么这个按钮比停止调试再启动调试更快。

固定,值的位置

有时候我们希望直接观察变量的值,而不是移动鼠标到变量上时才能观察,就可以将它固定下来。

下图中,将鼠标移动到变量上,弹出的小框右侧有一个图书钉样式的符号,点击它即可实现效果。
在这里插入图片描述

获取变量的内存地址

在调试状态中,对某个变量选择 Add Watch 操作
在这里插入图片描述
双击红色框的部分,键入 & 符号,即可获得内存地址
在这里插入图片描述
按 【Debug】-【Windows】-【Memory】的顺序点击选择内存视图
在这里插入图片描述
复制内存地址到红框中,即可查看其在内存中的值
在这里插入图片描述

调试时变量值的进制转换

在调试的时候,有些变量值我们希望 visual studio 能以 10 进制的方式展示出来,而不是 16 进制。

如下图,storeLoc 指针指向 numDec 的地址,在 watch 窗口中,我们可以通过 numDec 的地址拿到 numDec 的值,但是这个值是以 16 进制展示的,即 0x0000000a(也就是 10)
在这里插入图片描述
要实现进制的转换非常简单,只需要右击 0x0000000a 然后取消 16 进制展示即可
在这里插入图片描述
之后就可以看到 10 进制的值了
在这里插入图片描述
【注】你可以直接在鼠标移动到编辑器中的变量上时,实现这个转换,但因为我的截图工具不能截图这种悬浮的效果,所以通过 watch 窗口展示

其他

烫烫烫与屯屯屯

在 VC 下调试的过程中,有一些没有初始化的变量,我们可以看到它的值是“烫烫烫
在这里插入图片描述
这是什么原因呢?其实,在 Debug 模式中,所有分配的栈空间的每个字节都会初始化成 0xCC 这个值(汉字编码就是烫),之所以会是这个值,主要是方便判断一个变量有没有初始化,在【获取变量的内存地址】这一小节的第三,四幅图中,你可以看到未初始化的内存地址都是 CC 的值。

当然这和编译器有关,有些编译器选择 0xCDCDCDCD 作为未初始化的标记,这样我们就会看到“屯屯屯”的字样。

关于类似 0xCDCDCDCD 这样的值的含义,你可以通过这个链接了解到更多。

参考

  1. 零基础调试的方法
  2. 初步了解 Visual Studio 调试器
  3. 在 Visual Studio 中使用跟踪点将信息记录到“输出”窗口中
  4. Use breakpoints in the Visual Studio debugger
  5. Troubleshoot Breakpoints in the Visual Studio Debugger
  6. 《程序员的自我修养 – 链接,装载与库》
  7. 如何使用vs在调试时查看内存
  8. C/C++ 中利用debug宏定义打开/关闭调试输出
  9. C调试宏DEBUG的定义与使用
  10. 调试程序文档 :2022
  11. Debugging in Visual Studio:2015
  12. VS中的Modules窗口
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【教程】visual studio debug 技巧总结 的相关文章

随机推荐

  • mysql(mariadb)忘记密码

    root 64 localhost cat etc my cnf mysqld skip grant 添加这一行可以跳过验证 datadir 61 span class hljs keyword var span lib mysql soc
  • 「实验记录」MIT 6.S081 Lab4 traps

    Lab4 traps I SourceII My CodeIII MotivationIV Backtrace moderate i Motivationii SolutionS1 RISC V 栈帧结构S2 遍历所有栈帧 iii Resu
  • 「实验记录」MIT 6.S081 Lab11 networking

    Lab11 networking I SourceII My CodeIII MotivationIV SolutionV ResultVI Reference I Source MIT 6 S081 2020 课程官网Lab11 netw
  • 「Flask入门」通过路径名访问index.html主页

    先要在 app flask 目录下创建 templates 文件夹 xff0c 目录树如下 xff0c app flask venv templates hello py 在 templates 路径下新建 index html 主页 xf
  • 「Flask入门」在index.html中显示md

    首先要在云服务器上下载 marked 插件 xff0c 命令如下 xff0c span class token function npm span span class token function install span marked
  • 「格式技巧」word中删除空白页

    一 修改行间距 段落行间距设为固定值 1 磅 二 去掉分节符 找到 视图 里的 大纲 xff0c 将文章中多余的分节符删掉即可 xff0c 如下图红框处 xff0c
  • c语言实现10个数由小到大排序(冒泡法)

    10个数由小到大排序 xff1a 冒泡法 主要注意外层循环和内层循环的终止值 xff0c 可以考虑成3个数比较大小 xff0c 共需要2趟 xff0c 第一趟比较2次 xff0c 第二趟比较1次 xff1b 那么10个数比较大小 xff0c
  • debian系统使用NTP服务器并自动同步时间

    1 安装NTP工具 sudo apt install ntpdate span class token operator span y 以上只是安装成功 2 更改时区 sudo dpkg span class token operator
  • go 的时间操作

    未完 前言 本篇所有输入 xff0c 均用 p 代替 span class token comment 用 p 简写 span p span class token operator 61 span fmt span class token
  • Vm挂载虚拟硬盘(傻瓜式教程)

    Vm挂载虚拟硬盘 xff08 傻瓜式教程 xff09 第一步 xff1a 添加虚拟磁盘 打开vm xff0c 单机选择红帽的系统 编辑虚拟机设置 点击下面的添加 选择硬盘然后下一步 如果没有特殊的磁盘格式要求就默认推荐就好了 使用物理硬盘
  • 【学习笔记】在 Github Page 上托管基于 Vue 的项目

    环境 vscode 前言 本篇博文仅仅提供如何将 vue 项目部署在 github page 的基本操作 xff0c 至于项目的内容由读者自己决定 同时这是最基本的操作 xff0c 所以在复杂的项目部署中 xff0c 请根据具体情况 xff
  • 【学习笔记】查看你正在使用的 C++ 标准

    目录 查看 C 43 43 标准查看你的 gcc xff0c g 43 43 版本C 43 43 标准与 gcc 编译器的版本的对应关系C 43 43 标准与 Visual studio 的对应关系Visual studio 版本与 C 4
  • 【学习笔记】C++ 中的 virtual 关键字与虚函数

    目录 先决条件前言演示示例virtual 关键字的作用虚函数的规则参考与拓展深入拓展 先决条件 了解 C 43 43 中的多态这个概念 前言 virtual 关键字是面对对象中 xff0c 用于修饰类中的成员函数的关键字 被 virtual
  • 【经典回顾】HTTP 的请求与响应报文

    文章目录 前言请求报文请求行方法URL版本 首部行实体主体 响应报文状态行首部行实体主体 参考与拓展 前言 基于 HTTP1 1 xff0c 也就是目前最常用的 HTTP 协议版本 xff0c 涉及部分 HTTP 2 请求报文 让我们先来看
  • 【学习笔记】go 生成随机数

    目录 核心代码示例参考与拓展 核心 go 的标准库 xff08 math rand xff09 中已经为我们提供了产生伪随机数字的核心方法 xff0c 它们分别是用于产生种子的 rand Send value 和用于产生伪随机数的 rand
  • 【教程】油猴脚本开发入门教程

    目录 先决条件配置本地开发环境 可选 快速插入复杂的 HTML设置 CSS 样式发布与更新你的脚本常见标签简析 96 64 connect 96 96 64 grant 96 96 64 include 96 96 64 require 9
  • 【学习笔记】memcpy_s 函数与坑

    目录 函数原型函数描述参数描述返回值坑参考拓展 函数原型 errno t span class token function memcpy s span span class token punctuation span span clas
  • 【学习笔记】指向常量的指针和常量指针

    目录 指向常量的指针常量指针对比指向常量的指针与常量指针拓展参考 指向常量的指针 指向常量的指针 xff0c 即 pointer to const xff0c 即指针指向的是一个常量 xff0c 你应该把这个词 xff08 指向常量的指针
  • 【学习笔记】内存的连续分配管理方式

    目录 先决条件单一连续分配固定分区分配动态分区分配补充内部碎片和外部碎片基于顺序搜索的动态分区策略 xff08 算法 xff09 参考与扩展 先决条件 这里介绍的这些内存分配方式都是非常古老的内存分配方式 xff0c 基本已经不在现代操作系
  • 【教程】visual studio debug 技巧总结

    更新中 基础的调试技巧基本更新完毕 xff0c visual studio 提供了强大的调试功能 xff0c 许多东西需要大家动手体验 目录 环境调试器的基本使用更改执行流断点基本的断点操作跟踪点条件断点条件表达式命中次数过滤器 函数断点缩