Visual Studio调试之断点技巧篇
原文链接地址:http://blog.csdn.net/Donjuan/article/details/4618717
函数断点
在前面的文章Visual Studio调试之避免单步跟踪调试模式里面我讲了如何设置函数断点,说实话,我个人喜欢设置函数断点,而不是在代码行里面设置断点。一般来说,函数断点在下面几种情形下有用:
1. 例如调试一个网站程序,你通过分析网站的日志发现最有可能发生错误的函数,打开调试器并将调试器附加到程序上去,设置函数断点,重新执行网站……这样做的好处是,不用到处打开源文件去找出错的源代码行,调试器会自动打开源代码,并且在函数的入口处中断(岂不是很方便?)。
2. 例如你在阅读源代码的时候,通常在读到虚函数调用的时候,因为通常这种调用都是通过基类指针调用的,而你又一时半会不知道到底有哪个继承类的Overloading函数会被调用到,函数断点可以告诉你。
3. 或者一种特殊的情形,你想读一个程序的源代码,但就是找不到入口Main函数,例如.NET程序,那么直接在Visual Studio里面按F11就能帮你找到入口函数—这是函数断点的一个特殊情形。
4. 比如你在调试Web Service函数,设置函数断点也是一个快捷的调试方法,这个技巧跟技巧1类似。
当然,可能有些读者没有办法成功设置函数断点,如果设置函数断点失败,请阅读我的文章“不能设置断点的检查步骤”。如果里面有一些名词术语(术语请参看文章:调试术语)不知道或者不知道如何设置的话,呃,我会另写一篇文章讲解。
断点编程
有的时候你可能会碰到这种情况,触发一个断点以后,你发现需要修改一些值,才能使程序继续正确执行下去。例如我以前在中文版本的操作系统上,使用sscli里面(调试版)的csc.exe编译器编译一些包含语法错误或者语法警告的C#源文件的时候,csc.exe总是会莫名其妙地报告内部严重错误,然后就崩溃了。我将调试器附加上去以后,发现是一个ASSERT错误,ASSERT(lcid == 0x409),表示sscli里面的csc.exe总是默认自己在英文操作系统(或者说英文环境)里面运行。而且这一条语句会被执行很多次,手工修改lcid的值的确有点麻烦。然后我找源代码找来找去都没有找到csc.exe在哪个地方获取到这个lcid值(当然我最后找到了,下一个技巧将告诉你我是怎么找到的),然而我又不想重启系统(呃……也许我就是那种宁愿花1个钟头去找节省花费5分钟重启系统的方法的那种人……)。
这个时候如果调试器可以自动帮你重置lcid的值该有多好?幸运的是,Visual Studio提供了方法让你完成这样的工作。下面是一个简化的代码,因为我一时半会找不到sscli了:
int lcid = System.Globalization.CultureInfo.CurrentUICulture.LCID;
Console.WriteLine("lcid = {0}", lcid);
上面的代码在正常情况下,应该返回当前操作系统语言的lcid值,例如英文就是1033,中文的,呃……我忘记了。假设我们现在希望做的是,每当lcid的值为1033的时候,就自动更正为0。我们需要:
1. 在Console.WriteLine这一行上设置一个条件断点,条件断点的设置请参看Visual Studio调试之断点进阶篇:

2. 点击Visual Studio菜单栏里面的“工具(Tools)”—“宏(Macro)”—“宏资源管理器(Macro Explorer)”。然后创建一个新的宏:
Imports System
Imports EnvDTE
Imports EnvDTE80
Imports EnvDTE90
Imports System.Diagnostics
Imports Microsoft.VisualBasic
Imports Microsoft.VisualBasic.ControlChars
Public Module Module1
Sub ChangeExpression()
DTE.Debugger.ExecuteStatement("lcid = 0;")
End Sub
End Module
上面DTE.Debugger.ExecuteStatement的作用,你可以理解成在立即窗口中执行lcid = 0;这条语句。
3. 右键点击刚才设置好的断点,在菜单里面选择“When Hit …”,这一次在“When Breakpoint is Hit”窗口中勾选“Run a macro:(执行一个宏)”,然后在下拉框里面选择刚才你创建的宏的名称。如果你是第一次创建宏,名称应该是:Macros.MyMacros.Module1.ChangeExpression。
4. 勾选“继续执行(Continue execution)”,因为我们并不想让程序中断下来。
5. 点击确定以后,执行程序看一看结果,lcid是不是已经被自动改成0了?

数据断点
注意,这个技巧仅对C++程序调试有效(或者说native程序),而且你只能在中断模式下才能设置数据断点,另外你还只能在本机设置数据断点。
上一节的例子里,我们提到了,有的时候一个全局变量被修改了以后,你可能都找不到它是什么时候被修改的,于是夜已深,人已寐,你还在辛苦地调试到底是哪个鬼地方把这个变量的值修改了。F11, F10,……,SHIFT + F11,……,F5,靠,调过了,重来,F11,F10,……
这种情况下,数据断点就很有用了,Visual Studio允许你在变量被修改的时候,中断程序的执行,是不是很酷?
默认情况下,你是找不到数据断点这个菜单的,需要执行下面的步骤把它拉出来:
1. 打开你要调试的项目。
2. 点击Visual Studio菜单栏里面的“工具(Tools)”—“自定义(Customize…)”。然后在“自定义(Customize…)”窗口中选择“命令(Commands)”页签里面的“种类(Categories)”列表框里的“调试(Debug)”,找到“新数据断点(New Data Breakpoint)”,将它拖到菜单栏里面相应的位置。
然后打开或者创建一个C++项目,我们以下面的源代码为例子:
#include "stdafx.h"
int g_Variable = 0;
int _tmain(int argc, _TCHAR* argv[])
{
printf("Before modifying data breakpoints/n");
g_Variable = 1;
printf("After modifying data breakpoints/n");
return 0;
}
我们现在要Visual Studio在更改g_Variable的时候中断程序的执行。
1. 单击F11,这样程序就会在_tmain函数里面中断了,我们也就有机会设置数据断点了。
2. 点击菜单里面的“新数据断点(New Data Breakpoint)”。注意,数据断点是通过监视内存地址某一段区域更改来实现的,因此你必须提供一个内存地址(或者说就是指针吧),这里g_Variable是一个整形变量,因此你需要使用“&g_Variable”的形式来创建一个数据断点,因为整形的 大小是4个字节,因此数据断点监视的区域是4个字节,如下图所示:

3. 继续程序的执行,这时会弹出一个对话框,告诉你有一个内存地址的内容发生了变化(说明我们的数据断点生效了),这时代码行指向的是数据被修改的下一行代码,为什么会是下一行代码,下一篇文章会讲到:

呃,为什么数据断点只能在C++/C程序中才能设置?是因为托管代码有垃圾回收。而数据断点的执行原理应该是Windows内存管理里面的Guard Pages概念和VirtualProtectEx函数的实现。这个概念可以自己去查MSDN的内存管理方面的文档。
Visual Studio调试之断点技巧篇的更多相关文章
- Visual Studio调试之断点技巧篇补遗
原文链接地址:http://blog.csdn.net/Donjuan/article/details/4649372 讲完Visual Studio调试之断点技巧篇以后,翻翻以前看得一些资料和自己写 ...
- Visual Studio调试之断点进阶篇
Visual Studio调试之断点进阶篇 在上一篇文章Visual Studio调试之断点基础篇里面介绍了什么是断点,INT 是Intel系列CPU的一个指令,可以让程序产生一个中断或者异常.程序中 ...
- Visual Studio调试之断点基础篇
Visual Studio调试之断点基础篇 我曾经问过很多人,你一般是怎么调试你的程序的? F9, F5, F11, F…… 有很多书和文章都是介绍怎么使用Visual Studio编写WinForm ...
- VISUAL STUDIO 调试
调试术语 Visual Studio调试之断点基础篇 Visual Studio调试之断点进阶篇 不能设置断点的检查步骤 Visual Studio调试之断点技巧篇 Visual Studio调试之断 ...
- Visual Studio调试之避免单步跟踪调试模式
Visual Studio调试之避免单步跟踪调试模式 写完Visual Studio调试之断点进阶篇之后,想分享一下我常用的一些调试技巧,后面发现写之前,一些背景知识需要介绍一下. 下面是几篇今年2月 ...
- Visual Studio调试之符号文件
原文链接地址:http://www.cnblogs.com/killmyday/archive/2009/10/14/1582882.html 前面在不能设置断点的检查步骤和Visual Studio ...
- [转]Visual Studio调试之符号文件
http://www.cnblogs.com/killmyday/archive/2009/10/14/1582882.html 前面在不能设置断点的检查步骤和Visual Studio调试之断点进阶 ...
- 12个Visual Studio调试效率技巧
在这篇文章中,我们假定读者了解VS基本的调试知识,如: F5 开始使用调试器运行程序 F9 在当前行设置断点 F10 运行到下一个断点处 F5 从被调试的已停止程序恢复执行 F11 步进到函数内(如果 ...
- Visual Studio 调试技巧[Command Window & Immediate Window ](Tips)
Visual Studio 调试技巧[Command Window & Immediate Window ](Tips) 1. immediate window 定义的一些 alias (// ...
随机推荐
- MongoDB在单机上搭建分片副本集群(windows),版本二
配置可以参考前面一篇 https://www.cnblogs.com/a-horse-mosaic/p/9284010.html 副本集是一组服务器,其中有一个主服务器(primary),用于处理客户 ...
- Learning Experience of Big Data:The First Day-Try to set up a network connection on my virtural machine
After we install our virtual machine,the first thing we should do is to set up a network connection ...
- pynlpir + pandas 文本分析
pynlpir是中科院发布的一个分词系统,pandas(Python Data Analysis Library) 是python中一个常用的用来进行数据分析和统计的库,利用这两个库能够对中文文本数据 ...
- centos编译安装rabbitmq
安装环境 [root@VM_12_50_centos rabbitmq]# uname -a Linux VM_12_50_centos 3.10.0-514.21.1.el7.x86_64 #1 S ...
- latex02-LaTeX源文件的基本结构
1.一个latex文件有且仅有一个document环境 %后表示注释 2.latex的导言区用于全局设置. 例如:title\author\date 加入空行是结构更加清晰 为了能正确的使用标题信息, ...
- 登録更新(BAPI)
購買管理(MM) * [BAPI_REQUISITION_CREATE] 購買依頼登録 * [BAPI_REQUISITION_CHANGE] 購買依頼変更 * [BAPI_REQUISITION_D ...
- WPF中的命令与命令绑定(一)
原文:WPF中的命令与命令绑定(一) WPF中的命令与命令绑定(一) 周银辉说到用户输入,可能我们更多地会联想到 ...
- 洛谷P2307 迷宫
怎么又是一道叫迷宫的题呀QWQ 题目链接 这道题主要是对并查集的考察,需要注意的坑点在于有可能存在的不止一个联通块. 我们只需要对输入的两个数据进行判断,如果在一个集合中证明有多条路则输出0,如果不在 ...
- 关于 spring-aop理解
对于Aop 一直理解很是不到位 谈谈自己理解! Aop : Aspect: 切面 joinpoint 连接点 pointCut 切点 Advice 增强 targert 目标对象 w ...
- 程序在Linux下前后台切换
程序在Linux下前后台切换 一.为什么要使程序在后台执行 背景:SecureCRT远程连接到linux主机,使程序在后台运行有以下好处: (1)本机关机不影响linux主机运行 (2)不影响计算效率 ...