1 导言
在软件开发周期中,测试和修正缺陷(defect,defect与bug的区别:Bug是缺陷的一种表现形式,而一个缺陷是可以引起多种Bug的)的时间远多于写代码的时间。通常,debug是指发现缺陷并改正的过程。修正缺陷紧随debug之后,或者说二者是相关的。如果代码中存在缺陷,我们首先要识别造成缺陷的根本原因(root cause),这个过程就称作调试(debugging)。找到根本原因后,就可以修正缺陷。
那么如何调试代码呢?Visual Studio提供了很多用于调试的工具。有时调试需要花费大量时间去识别root cause。VS提供了许多辅助调试的便捷的工具。调试器(Debugger)包含错误列表、添加断点、可视化的程序流程、控制执行流程、Data Tips、监视窗口(watch windows)、多线程调试、线程窗口、并行调试概览以及IntelliTrace调试概览。我希望本文能够对调试功能的使用者有所裨益。请注意,本文使用VS2010。某些功能在旧版本中也是一致的,但是VS2010新增了许多features(Labeling breakpoint, Pinned DataTip, Multithreaded Debugging, Parallel debugging and IntelliTrace)。
可以通过VS的调试(Debug)菜单启动调试。点击调试菜单下的"启动调试"或者按F5键启动。如果你已经在代码中加入了断点,那么执行会自动开始。
通常我们通过在可能存在问题代码处加断点来启动调试。因此,我们从断点开始讲起。
class Program
{
static void Main(string[] args)
{
string[] strNames = { "Name1", "Name2", "Name3", "Name4", "Name5", "Name6" }; foreach (string name in strNames)
{
Console.WriteLine(name); // BreakPoint
}
int temp = 4;
for (int i = 1; i <= 10; i++)
{
if (i > 6)
temp = 5;
}
} public static void Method1()
{
Console.WriteLine("Break Point in Method1"); // BreakPoint
} public static void Method2()
{
Console.WriteLine("Break Point in Method2"); // BreakPoint
Console.WriteLine("Break Point in Method2"); // BreakPoint
} public static void Method3()
{
Console.WriteLine("Break Point in Method3"); // Breakpoint
}
}
执行程序将停在第一个断点处。下图给出了断点列表。
图: 断点列表
上图中Labels列都为空。下面介绍如何给断点设置标签(label)以及如何使用标签。只需在特定代码行的断点符号上右击(①)或者在断点窗口中设置(②)即可对任何断点设置标签。
图: 设置断点标签(Setting Breakpoint Label)
右击断点,点击编辑标签(Edit Labels),即可对任意断点添加标签。对于示例代码,我为所有断点的标签起了易于理解的名字。
图: 添加断点标签(Adding Breakpoint Label)
这些标签如何辅助我们调试呢?现在,所有断点都是使能的(enabled)。如果你不想调试method2,一般情况下你必须去对应的方法中一个一个的取消断点,但这里你可以通过标签名过滤或者搜索它们,然后选中它们以方便的取消它们。
图: 使用标签过滤断点(Filter Breakpoint Using Labels)
断点标签到此介绍完毕。我举的例子非常简单,但是断点标签在你调试大量代码,多个工程等情况下非常有用。
3.3 条件断点(Conditional Breakpoint)
假设你在多次迭代(循环)处理数据而你只想调试其中某几次迭代。这意味着你想根据某些特定条件暂停你的程序。Visual Studio断点允许你设置条件断点。当且仅当条件满足时,调试器才会停住。
首先,你需要在你想暂停执行处设置断点。然后右击红色的断点图标。右键菜单中点击"条件"。
图: 设置断点条件(Set Breakpoint Condition)
点击右键菜单中的"条件"后,会弹出下面的对话框设置断点的条件。
图: 断点条件设置
假设你要调试下面的代码块:
class Program
{
static void Main(string[] args)
{
string [] strNames = { "Name1","Name2", "Name3", "Name4", "Name5", "Name6"}; foreach(string name in strNames)
{
Console.WriteLine(name); // Breakpoint is here
}
}
}
你在Console.WriteLine()语句处设置了断点。当执行程序时,每次for-each循环都会停住。如果你想让代码只在name="Name3"时停住,该怎么办呢?非常简单,你只需使用条件name.Equals("Name3")。
图: 设置断点条件
查看断点符号。它应该看上去像是一个加(+)号在断点符号内部,这表示该断点是条件断点。
图: 条件断点符号(Conditional Breakpoint Symbol)
设置断点的条件之后,在调试程序,调试器只会在满足给定条件时才停住。
图: 条件断点命中(Conditional Breakpoint hit)
条件输入框的自动补全(intellisense):上面给出的断点条件非常简单,可以非常容易的写到条件文本框中。有时你可能需要定义很大很复杂的条件。不必担心,VS为条件文本输入框也提供了自动补全功能。因此,在条件框中输入就像是在编辑器中一样方便。如下图。
图: 条件文本框的自动补全(intellisense in condition textbox)
我几乎讲解了条件断点的所有内容。除了下面这点。在条件窗口中有两个选项:
- Is True
- Has Changed
我们已经看到"Is True"选项的用途了。"Has Changed"用在当你想在某些值变为某些特定值的时候停住。
3.4 导入/导出断点(Import / Export Breakpoint)
3.5 断点命中计数(Breakpoint Hit Count)
你可以限制断点只对特定进程或线程有效。这在进行多线程程序的调试时非常有用。右击断点选"筛选器"即可打开筛选器窗口。
在筛选规则中,你可以设置进程名,进程Id,机器名,线程ID等。我会在多线程调试小节中详述其用法。
图: 调试时的数据便签(DataTips During Debugging)
几个月前,我发过一篇关于VS 2010 DataTip Debugging Tips的文章。
4.1 Pin Inspect Value During Debugging
4.4 Last Session Debugging Value
4.6 Change Value Using Data Tips
列出当前方法中的所有变量。当调试器停在某特定断点并打开Autos窗口时,将展示当前范围中与此值相关的变量。
这些变量由VS调试器在调试的时候自动检测。VS检测与当前语句相关的对象或变量,基于此列出Autos变量。Autos Variable的快捷键是Ctrl + D + A。
Watch窗口用于添加变量。你可以添加任意多个变量。添加方法是,右击变量并选择"Add to Watch"。
也可以使用拖放(Drag and Drop)将变量添加到监视窗口中。从监视窗口中删除变量的方法是,右击变量并选择"Delete Watch"。通过调试窗口,也可以在运行时编辑这些变量值。
若果变量中含有对象实例,左边会有一个"+"号用于查看对象的属性和成员。
在对特定对象变量创建Object ID之后,Visual Studio会给这个对象添加一个数码和"#"号,用来表示。
图:基本即时窗口(Basic Immediate Window)
这是对所有开发人员来说最为常用的特性,因此我就不一一介绍即时窗口的每一条命令了。
8 调试多线程程序(Debugging Multithreaded Program)
8.3 Break Point Filter - Multithread Debugging
9 调试并行程序(Debugging Parallel Program)
9.1 Parallel Task and Parallel Stacks
10 Debugging with IntelliTrace
10.2 Mapping with IntelliTrace
11 调试常用快捷键(Useful Shortcut Keys For VS Debugging)
Shortcut Keys | Descriptions |
Ctrl-Alt-V, A | Displays the Auto window |
Ctrl-Alt-B | Displays the Breakpoints dialog |
Ctrl-Alt-C | Displays the Call Stack |
Ctrl-Shift-F9 | Clears all of the breakpoints in the project |
Ctrl-F9 | Enables or disables the breakpoint on the current line of code |
Ctrl-Alt-E | Displays the Exceptions dialog |
Ctrl-Alt-I | Displays the Immediate window |
Ctrl-Alt-V, L | Displays the Locals window |
Ctrl-Alt-Q | Displays the Quick Watch dialog |
Ctrl-Shift-F5 | Terminates the current debugging session, rebuilds if necessary, and starts a new debugging session. |
Ctrl-F10 | Starts or resumes execution of your code and then halts execution when it reaches the selected statement. |
Ctrl-Shift-F10 | Sets the execution point to the line of code you choose |
Alt-NUM * | Highlights the next statement |
F5 | If not currently debugging, this runs the startup project or projects and attaches the debugger. |
Ctrl-F5 | Runs the code without invoking the debugger |
F11 | Step Into |
Shift-F11 | Executes the remaining lines out from procedure |
F10 | Executes the next line of code but does not step into any function calls |
Shift-F5 | Available in break and run modes, this terminates the debugging session |
Ctrl-Alt-H | Displays the Threads window to view all of the threads for the current process |
F9 | Sets or removes a breakpoint at the current line |
Ctrl-Alt-W, 1 | Displays the Watch 1 window to view the values of variables or watch expressions |
Ctrl-Alt-P | Displays the Processes dialog, which allows you to attach or detach the debugger to one or more running processes |
Ctrl-D,V | IntelliTrace Event |
Step Into(逐语句):执行并移动到下一条语句(实际上,跳入上一条语句的代码块,此代码块的第一条)
Step Over(逐过程):执行并跳到下一条语句,但不进入上一条语句的代码块
[1] Mastering Debugging in Visual Studio 2010 - A Beginner's Guide
[2] bug和缺陷的区别