C++调试和诊断

[原文发表地址] https://blogs.msdn.microsoft.com/vcblog/2017/04/10/c-debugging-and-diagnostics/

[原文作者] Adam Welch (MSFT)

[原文发表时间] 2017/4/10

 

调试是软件开发的基石之一,它可以消耗开发人员一天中的很大一部分。Visual Studio自带的调试器提供了强大的功能和丰富的体验,用于查找和修复出现在你应用程序中的问题,无论什么类型的问题或者有多么难解决。事实上,Visual Studio中有非常多的调试功能和工具,这可能对新用户来说有点复杂。本博客将会让你快速了解Visual Studio自带调试器以及它如何在C ++开发的所有领域中帮助你。

 

内容目录

  • 断点和流程控制
  • 数据检验和可视化
  • 诊断工具和性能分析
  • 调试过程和策略
  • 多线程调试
  • 编辑并继续
  • 其他资源

断点和流程控制

在你使用Visual Studio构建完你的应用程序后,你就可以通过按F5来启动调试器了。当你启动调试器后,下面这些命令可以帮助你来导航你程序中的断点,以便你控制程序的状态和调试器的当前上下文。这些命令可以让你灵活的控制调试器的作用范围,比如你想调查的某一行或某一个函数。

  • 继续F5:执行到下一个断点
  • 逐过程F10:执行代码的下一行然后停止
  • 逐语句F11:进入当前代码行调用的函数中
  • 跳出Shift+F11:跳出当前函数并停在函数调用后的下一个可执行语句

当鼠标悬停在你代码中的一个断点上时,你将看到两个图标。右边的图标有两个圆圈允许你快速切换当前断点开启或关闭而不用取消这个断点标记:

左边的图标将会启动断点的选项列表。在这里你可以给断点添加条件或者操作。

bpmenu

有时候你想让断点在满足一定条件后被触发,比如当调试器范围内的一个变量x <= 5成立时。使用Visual Studio内置断点设置窗口可以很容易的设置条件断点,断点设置窗口允许你很方便地在源代码查看器中给你的代码直接添加条件断点而不用去申请一个模态窗口。注意,断点图标上出现一个“+”表示至少有一个条件已经被添加到了这个断点上。

这里还有一个叫做断点操作的设置可以在断点中一些操作,例如打印进程ID或者调用堆栈。Visual Studio通常将这些断点中的操作称为“断点追踪”。内置断点设置窗口允许你设置各种各样的断点操作,如打印调用堆栈或PID。注意,当断点中包含至少一个操作时,断点图标会变成菱形。在下面的例子中,我们给断点同时添加了条件和操作,这使得断点图标变成了一个中间带“+”的菱形。 inlinebp2

当调试时遇到一个特定的函数时,函数断点监视点)就会激活。使用调试菜单并选择新建断点来添加一个函数断点。

functionbp

当调试时遇到一个特定的地址时,数据断点就会启动。使用调试菜单并选择新建断点来添加一个数据断点。

 

数据检验和可视化

当你停在一个断点上时,调试器就可以访问变量的名字和其当前在内存中的值。这里有几个窗口可以允许你查看这些对象的内容。

  • 局部变量:局部变量窗口会列出当前调试范围内的所有变量,通常包括当前函数到目前为止所有的静态和动态的内存分配。
  • 自动:这个窗口提供了一个源自以下内容的内存中的变量列

设置了断点的当前行

注意在下面的例子中,第79行并没有执行。因为变量没有初始化,所以在自动窗口中没有数值显示。

代码的前三行。如你所见,当我们停在断点所在的79行,前三行的数据都会显示,并且当前行已被检测到等待执行,但是数据必须在本行执行完成后才可见。

code1 autos

  • 监视:这些窗口允许你在调试程序时追踪你感兴趣的变量。列表中的变量只有处在调试范围内才可以查看。
  • 快速监视是被设计用来在以后查看变量内容而不用将变量存储在查看窗口中的。由于这是一个模态对话框,它并不是在整个调试阶段中追踪变量的最好的选择:这种情况下监视窗口是一个更好的选择。

quickwatch

  • 内存窗口:这些提供了更直接的系统内存视图,并且它们不受当前调试器所显示的限制。它们能提供按照位数排列的功能,比如16位,32位和64位。这个窗口的主要目的是为了查看原始格式化的内存内容。查看自定义数据类型是不支持的。

自定义内存视图

Visual Studio提供了一个Natvis框架使你能够自定义非原始的本地数据类型在变量窗口显示(局部变量,自动,监视)。我们将Natvis可视化工具迁移到了类库上,包括Visual C++ STL,ATL和MFC。这样易于去创建一个你自己的Natvis 可视化工具去自定义显示变量内容在上述的调试器窗口。

创建一个Natvis文件

你可以将Natvis文件添加到项目中或者作为一个exe项目的顶级解决方案。调试器可用natvis文件在一个项目/解决方案中。我们为创建一个natvis文件提供了一个嵌入式模板,在Visual C++ -> Utility文件夹下。

将可视化程序添加到你的项目中,通过源代码控制便于跟踪和存储。

更多关于怎么写.natvis可视化工具,请咨询Natvis文档

在调试时修改Natvis可视化工具

下面的动画展示了为Volcano类型编辑一个natvis将怎样改变调试器在变量窗口中的显示。顶上那行对象显示的字符串从m_EnglishName被改变成了m_nativeName。注意,不管,natvis文件怎么改变,调试器都会立刻做出改变并且改变的部分会显示为红色。

 

诊断工具和性能分析

大多数的分析工具都是以与调试器本身分离的特殊模式运行。在Visual Studio中,我们添加了一组性能和诊断工具,可以在调试过程中运行并提供关于你应用程序的性能和状态的更深入的了解。你可以控制应用程序的流程来达到问题区域,然后在深入问题后激活更加强大的工具,而不是等待问题发生。你可以完全控制程序并决定要分析哪些信息,无论是一个函数在CPU上花费了多少时间,或是按类型查看每一个分配了的内存利用率。你程序的实时CPU和内存利用率将显示在图表中,调试器时间会沿着时间轴显示。有一个选项卡用于使用每一个附带的诊断工具:CPU使用率和内存使用率。 dtwindow

CPU使用率

这个工具允许你在CPU图表中查看在所选时间范围内每一个函数被调用时的CPU使用率。你必须通过单击此选项卡左侧的“CPU分析”按钮来启动这个工具,才能选择时间范围进行分析。 cpuusage

内存利用率

这个工具使你能够使用内存分析器,使用堆分析按钮来启动本地分析,以便你能够截取堆快照。左侧的按钮用来截取快照,你可以通过点击快照列表中的蓝色链接来查看每一个快照的内容。

snapshotreel

类型视图显示从内存快照中解析的类型,包括内存占用的计数和总量。你可以通过双击此视图中的一行来导航到实例视图

typesview

实例视图显示从内存快照中解析的类型,包括内存占用的计数和总量。你可以通过双击类型视图中的一行来导航到实例视图。你也可以通过使用类型名称左侧的向后箭头导航回类型视图。

instancesview

堆栈视图显示你程序的调用堆栈并允许你浏览每一个被捕获的分配的调用路径。你可以通过选择视图模式下拉菜单中的堆栈视图从类型视图导航到堆栈视图。此页面的顶部显示完整的执行调用堆栈,并且用控件顶部右侧的聚合调用堆栈依据来按照被调用方或调用方排序(按顺序或反向)。下半部分将列出归属于调用堆栈所选部分的所有分配。扩展这些分配将显示它们的分配调用堆栈。

stacksview

 

调试过程和策略

附加到进程

在Windows机器上运行的任何进程都可以使用Visual Studio进行调试。如果你想要查看变量类型,请确保为要附加到的进程加载调试符号。 attach

远程调试

为了在另一台机器上进行远程调试,你需要通过网络连接到那台机器并在调试器下拉列表中启用远程调试。只要你通过网络连接到这台机器,你就可以进行调试而无论距离多远。你还可以轻松的调试运行在外部设备(如平板电脑)上的应用程序。

debugselector

在调试器属性页面上可以管理IP地址和详细连接信息,可以使用Alt+Enter或者右击解决方案资源管理器中的项目来进入调试器属性页面。 debugpp

多线程调试

Visual Studio提供了几个强大的窗口来帮助调试多线程应用程序。并行堆栈窗口是调试多线程应用程序时很有用的一个工具。它的线程视图显示了应用程序中所有线程的调用堆栈信息。它允许你在这些线程的线程和堆栈块之间导航。在本地代码中,任务视图显示任务组并行算法异步代理轻量级任务的调用堆栈。

parallelstacks

还有一个并行监视窗口专门用于跟踪不同线程上的变量,将每一个线程作为一行显示,将每一个被观测对象作为一列显示。你还可以评估数据上的布尔表达式并将数据导出到电子表格(.csv或Excel)来进一步分析。 parallelthreads

 

编辑并继续

编辑并继续允许你在调试期间编辑你代码的某些部分而不必去重新构建,这节省了大量的开发时间。此功能在默认情况下是开启的,并且可以使用调试选项进行切换或自定义,可以通过调试菜单访问并选择选项

 

其他资源

如果你对Visual Studio中有关调试的更多内容和视频感兴趣,请查看以下链接:

 

博客帖子

 

相关文档

 

视频