中关村在线

软件

Visual Studio调试技巧

遇到异常时中断执行,便于调试和排查问题。

1、 意外中断

2、 异常发生时可启动调试器中断程序,便于在问题出现后立即进行调试。通过查看调用栈,能快速定位异常根源,有助于深入分析和解决问题。

3、 在Visual Studio中,可自定义中断调试的异常类型。通过选择调试菜单下的异常选项,打开相关设置对话框。在此可配置原生或托管异常,不仅支持系统默认的异常类型,还允许用户添加自定义异常,以便在程序运行过程中精准捕获特定错误,提升调试效率与问题排查能力。

4、 当 std::exception 被抛出时,调试器将触发中断以进行异常调试。

5、 技巧二:利用Watch窗口的伪变量功能

6、 监视窗口或快速监视对话框中包含一些调试器识别的特殊变量,称为伪变量。相关内容在文档中有详细说明。

7、 当前线程的唯一标识号码

8、 进程标识符,用于唯一识别进程

9、 启动程序时所使用的命令行参数字符串。

10、 当前运行程序的用户账户信息。

11、 显示指定寄存器 registername 中存储的数据内容。

12、 无论如何,最后一个错误的伪变量都极具实用价值。

13、 显示最近一次错误的错误代码。

14、 显示最近一次错误的详细信息

15、 越界后检查堆中对象状态

16、 当调试过程中发生符号越界,虽然对象依然存在,但监视窗口中的变量会变灰,无法查看或更新。此时若已知对象的内存地址,便可将其转换为对应类型的指针,并添加到监视窗口中,从而继续观察其内部数据,实现对对象状态的完整跟踪与分析,有效提升调试效率。

17、 在以下示例中,单步跳出do_foo()后,_foo原本无法访问,但将其地址转换为foo*类型后,便可继续对该对象进行观察和操作。

18、 查看数组内容

19、 当处理一个较大数组(例如包含数百个元素,也可能更少)时,在调试器的监视窗口中直接展开并查找特定范围的元素往往十分不便,需要频繁滚动。尤其当数组位于堆上分配时,通常无法直接在监视窗口中展开查看其内容。针对这一问题,存在一种高效的替代方法。可以通过表达式 (array + ), 来查看从指定偏移位置开始的若干个连续元素,其中array代表数组的起始地址或指针,是起始索引,是要显示的元素个数。若希望观察整个数组的内容,只需输入 array, 即可一次性展示全部元素。这种方法不仅适用于栈上数组,也适用于动态分配在堆上的数组,极大提升了调试过程中对数组数据的浏览效率,避免了界面滚动带来的操作繁琐。

20、 若数组位于堆上,可在监视窗口中展开查看。要观察特定区间的元素,需采用如下格式:((T*)数组名 + 偏移量),数量,其中T为数组元素的类型。此方法同样适用于堆上的多维数组,通过指定起始偏移和元素个数,可准确显示所需数据范围。

21、 当你在使用MFC并采用其提供的数组容器(如CArray、CDWordArray、CStringArray等)时,同样可以应用类似的过滤方式。除此之外,你还需关注数组中的m_pData成员变量,因为该指针指向实际存储数据的内存缓冲区,通过访问它可直接操作底层数据内容。

22、 避免调用无用函数

23、 调试代码时,常会遇到需要跳过的函数调用,例如构造函数或赋值操作,其中最令人困扰的是CString的构造函数。比如,在单步执行take_a_string()函数时,调试器往往会先进入CString的构造函数,打断正常的调试流程,影响效率,令人颇为烦恼。

24、 {

25、 }

26、 {

27、 }

28、 幸运的是,可以配置调试器跳过特定的方法、类或整个命名空间。这一功能的实现方式经历了多次演变。在使用VS6的时代,通常通过修改autoexp.dat文件来设定。到了Visual Studio 2002,机制更改为依赖注册表配置。若要跳过某些函数,需在注册表中添加相应的键值(具体设置如下所示)。

29、 具体位置因所用Visual Studio版本及操作系统平台(x86或x64)而异,且注册表仅在64位Windows系统中可查看。

30、 值为数字,表示规则优先级,数值越大优先级越高。

31、 该值为REG_SZ类型,包含正则表达式,用于定义过滤与执行规则。

32、 为防止调用CString方法,我加入了如下规则:

33、 即便强制进入上述示例中的take_a_string(),启用此功能后,调试器也会自动跳过CString的构造过程。

34、 通过代码调用启动调试功能,实现程序运行时的实时调试与问题排查。

35、 你很少需要将调试器附加到程序上,但在Attach窗口中可能无法实现,因为中断发生太快而难以捕获。同时,也不能一开始就用调试器启动程序。为给调试器提供附加机会,可在程序中调用内部函数_degbugbreak()来主动触发中断,从而及时建立连接并进行调试操作。

36、 {

37、 }

38、 还有其他方式可实现,比如触发中断3,但这仅限于x86平台(C++64位已不再支持内联汇编)。此外,虽有DebugBreak()函数可用,但使用起来不够便捷。综合考虑,本文推荐采用内部方法来完成该操作。

39、 程序执行内部方法时会暂停,此时可趁机将调试器连接到该进程进行调试操作。

40、 在输出窗口显示内容

41、 调用DebugOutputString可在调试器输出窗口显示指定文本,若未连接调试器,则该函数不执行任何操作。

42、 阻断内存泄露

43、 内存泄漏是原生开发中一个不容忽视的问题,尤其在大型项目中,检测和定位泄漏尤为困难。Visual Studio 提供了内存泄漏检测功能,能够生成相关报告,辅助开发者发现问题。此外,也有多种免费或商业工具可用于协助排查内存泄漏。在某些特定情况下,当某次内存分配最终导致泄漏时,可通过调试器设置中断来追踪问题源头。然而,这通常需要确定可重现的内存分配编号,而这一过程往往较为复杂且不易实现。只有成功锁定该编号,调试器才能在程序运行至对应分配操作时准确中断,从而帮助分析泄漏原因。

44、 观察以下代码,分配了8个字节内存但未释放。Visual Studio会报告引发内存泄漏的对象,多次运行后可发现始终显示相同的分配编号(341),表明每次都是同一处内存未被释放,存在持续的内存泄漏问题。

45、 {

46、 }

47、 在特定可重现位置中断的操作步骤如下:

48、 确保掌握充分的内存泄漏报告方法,可参考CRT库相关检测技术。

49、 反复运行程序,直至在内存泄漏报告中发现可重现的分配编号,如示例中的(341),确保结果具有一致性与可追踪性。

50、 在程序起始处设置断点,可尽早实现中断调试。

51、 当首次中断触发时,watch窗口的名称栏将显示:{,,msvcr90d.dll}_crtBreakAlloc,在数值栏中输入你希望定位的编号即可进行查找。

52、 继续运行(F5)

53、 程序运行至设定位置时暂停,通过调用栈可定位触发该位置的具体代码段。

54、 通过上述步骤,利用分配的编号341,可准确定位上例中内存泄漏的根源。

55、 调试发布版本

56、 调试与发布分别服务于不同目标。调试配置专为开发过程设计,便于排查问题;发布配置则用于生成最终程序版本,需满足严格的发布质量标准,通常包含性能优化并禁用调试功能。有时需要对发布版本进行类似调试的操作,此时必须调整相关设置。然而一旦修改,实际上已不再是纯粹的发布版,而是融合了调试特性的混合版本,其行为可能与真正的发布版存在差异,因此不能完全代表最终产品的运行状态。

57、 你必须完成以下几件重要的事情。

58、 将C/C++的调试信息格式设置为程序数据库(/Zi),以确保生成完整的调试数据,便于在开发过程中进行有效的调试和错误排查,提升程序开发效率与稳定性。

59、 将C/C++的优化设置调整为禁用(/Od),确保在优化选项中选择Disabled(/Od)。

60、 在配置Linker的Debugging选项时,应将生成调试信息设置为是(DEBUG),以确保编译过程中包含必要的调试数据,便于后续问题排查和程序分析。

61、 所示

62、 远程调试技术

63、 远程调试是重要环节,常被提及,涉及内容广泛,此处仅作简要概述。

64、 请在远程设备安装调试监控软件。

65、 远程调试监控需以管理员权限运行,操作用户须为管理员组成员。

66、 运行监控时将启动一个新服务,该服务名称需与Visual Studio中附加到进程窗口的限定符下拉框中的值保持一致。

67、 远程与本地设备的防火墙需开放,确保Visual Studio与远程调试监控器正常通信。

68、 调试时PDB文件至关重要,要让Visual Studio自动加载,需满足特定条件。

69、 本地PDB文件需存在,且远程机器对应路径下应放置相同模块。

70、 远程机器上的托管PDB区域设置必须有效且可访问。

展开全文
人赞过该文
内容纠错

相关电商优惠

评论

更多评论
还没有人评论~ 快来抢沙发吧~

读过此文的还读过

点击加载更多

内容相关产品

说点什么吧~ 0

发评论,赚金豆

收藏 0 分享
首页查报价问答论坛下载手机笔记本游戏硬件数码影音家用电器办公打印 更多

更多频道

频道导航
辅助工具