Visual Studio 调试系列3 断点

断点是开发人员的工具箱中最重要的调试技术之一。 若要暂停调试程序执行所需的位置设置断点。 例如,你可能想要查看代码变量的状态或查看调用堆栈的某些断点。html

01 在源代码中设置断点

能够在任意可执行代码行上设置断点。 例如,在如下 C# 代码,能够设置断点在变量声明for循环中或内的任何代码for循环。 命名空间或类声明或方法签名,没法设置断点。express

若要在源代码中设置断点,请单击代码行旁边的最左侧边距中。 您还能够选择行,而后按F9,选择调试 > 切换断点,或右键单击并选择断点 > 插入断点。 断点显示为左边距中的一个红点。编程

调试时,执行的断点处暂停,在执行该行上的代码以前。 断点符号显示黄色箭头。windows

当调试器在断点处中止时,您能够查看应用程序,包括变量值和调用堆栈的当前状态。 有关调用堆栈的详细信息,请参阅如何:使用调用堆栈窗口安全

  • 断点是一个触发器。 您能够单击它,请按F9,或使用调试 > 切换断点删除或从新插入。编程语言

  • 若要禁用断点而不删除它,将鼠标悬停或右键单击它,而后选择禁用断点。 已禁用的断点显示为左边距中的空点或断点窗口。 若要从新启用断点,请将鼠标悬停或右键单击它,而后选择启用断点。编辑器

  • 设置条件和操做、 添加和编辑标签,或将断点导出,右键单击该和选择合适的命令,或将鼠标悬停其上,而后选择设置图标。函数

02 调用堆栈窗口中设置断点

若要中断的指令或调用函数返回到的行处,能够设置断点调用堆栈窗口。工具

在调用堆栈窗口中设置断点:visual-studio

  1. 若要打开调用堆栈窗口中,您必须在调试期间暂停。 选择调试 > Windows > 调用堆栈,或按Ctrl + Alt+C。

  2. 在中调用堆栈窗口中,右键单击调用函数,而后选择断点 > 插入断点,或按F9.

    调用堆栈的左边距中的函数调用名称旁边会显示一个断点符号。

调用堆栈断点显示在断点窗口具备对应于在函数中的下一步可执行指令的内存位置的地址。

调试器在指令处中断。

03 在反汇编窗口中设置断点
  1. 若要打开反汇编窗口中,您必须在调试期间暂停。 选择调试 > Windows > 反汇编,或按Alt + 8。

  2. 在中反汇编窗口中,单击想要中断的指令的左边距中。 此外能够选择它,而后按F9,或右键单击并选择断点 > 插入断点。

04 设置函数断点

当调用函数,能够中断执行。

若要设置函数断点:

  1. 选择调试 > 新断点 > 函数断点,或按Alt +F9 > Ctrl+B。

    您还能够选择新建 > 函数断点中断点窗口。

  2. 在中新函数断点对话框中,输入中的函数名称函数名称框。

    若要缩小范围的函数规范:

    • 使用彻底限定的函数名称。

      示例:Namespace1.ClassX.MethodA()

    • 添加剧载函数的参数类型。

      示例:MethodA(int, string)

    • 使用 ! 符号指定模块。

      示例:App1.dll!MethodA

    • 在本机中使用上下文运算符C++。

      {function, , [module]} [+<line offset from start of method>]

      示例:{MethodA, , App1.dll}+2

  3. 在中语言下拉列表中,选择该函数的语言。

  4. 选择 肯定。查看编辑器,全部 Draw() 方法处都以自动插入了断点。

05 设置数据断点 (.NET Core 3.0 或更高版本)

为特定对象的属性发生更改时,数据断点中断执行。

若要设置数据断点

  1. 在.NET Core 项目中,开始调试,并等待,直到到达一个断点。

  2. 在自动,监视,或局部变量窗口中,右键单击一个属性,而后选择值更改时中断的上下文菜单中。

    管理数据断点

在.NET Core 中的数据断点不适用于:

  • 不是可扩展的工具提示中,局部变量,自动或监视窗口属性
  • 静态变量
  • 使用 DebuggerTypeProxy 特性类
  • 在结构内的字段

 

06 在“断点”窗口中管理断点

可使用断点窗口来查看和管理你的解决方案中的全部断点。 此集中的位置是在大型解决方案中,或对于复杂断点很是关键的调试方案尤为有用。

在断点窗口中,您能够搜索、 排序、 筛选、 启用/禁用或删除断点。 您还能够设置条件和操做,或添加新的函数或数据断点。

若要打开断点窗口中,选择调试 > Windows > 断点,或按Alt+F9或Ctrl+Alt+B。

 若要选择要在列表中显示的列断点窗口中,选择显示列。 选择一个列标题以对断点列表,可按该列进行排序。

断点标签

可使用标签进行排序和筛选列表中的断点断点窗口。

一、若要将标签添加到断点中,右键单击该断点的源代码中或断点窗口中,并选择编辑标签。 添加新标签或选择一个现有证书,而后选择肯定。

二、对在断点列表进行排序断点经过选择窗口标签,条件,或其余列标题。 能够选择要经过选择显示的列显示列工具栏中。

07 断点条件

能够经过设置条件来控制在什么时候何处执行断点。 条件能够是调试器可以识别任何有效表达式。 有关有效表达式的详细信息,请参见调试器中的表达式

若要设置断点条件:

  1. 右键单击断点符号,而后选择条件。 或悬停在断点符号,选择设置图标,并选择条件中断点设置窗口。

    您还能够在设置条件断点窗口中的右键单击断点并选择设置,而后选择条件。

  1. 在下拉列表中,选择条件表达式,命中计数,或筛选器,并相应地设置值。

  2. 选择关闭或按Ctrl+Enter关闭断点设置窗口。 或者,从断点窗口中,选择肯定关闭对话框。

 

条件表达式

当选择条件表达式,能够选择两个条件:为 true或发生更改时。 选择如此时,知足表达式时中断或发生更改时表达式的值已更改时中断。

一、示例1,设置条件表达式为 true, index == 1

按下F5,启动调试,因为第一次 index 等于0,因此37行断点没有命中,直接走到43行的正常断点处。

第一次循环结束后,index的值增长了1,等于1。进入到第二次循环时,按下F5,因为 index = 1,知足设置的表达式,因此命中了37行的断点。

第二次循环结束后,index的值增长了1,等于2。进入到第三次循环时,按下F5,因为 index = 2,不知足设置的表达式,因此没有命中37行的断点,直接走到43行的正常断点处。

二、示例2:设置条件表达式为 更改时, index 

按下F5,启动调试,因为第一次 index 等于0,第一次进入循环,结束前 index的值未改变仍然为0,没有改变,因此37行断点没有命中,直接走到43行的正常断点处。

第一次循环结束后,index的值增长了1,等于1。进入到第二次循环时,按下F5,因为 index = 1,值更改了,知足设置的条件,因此命中了37行的断点。

第二次循环结束后,index的值增长了1,等于2。进入到第三次循环时,按下F5,因为 index = 2,值更改了,知足设置的条件,因此命中了37行的断点。

 若是使用无效语法设置断点条件,则会显示警告消息。 若是在指定断点条件时使用的语法有效但语义无效,则在第一次命中断点将出现警告消息。 在任一状况下,调试器将中断时它会命中断点无效。 仅在条件有效且计算结果为 false时才会跳过断点。

不一样编程语言的“更改时”字段的行为不一样 :

对于本机代码,调试器不会考虑更改,所以不会命中第一次计算断点条件的第一次计算。

对于托管代码,调试器命中断点后第一次计算发生更改时处于选中状态。

在条件表达式中使用对象 Id (C#和F#仅)

有些的时候,当你想要观察特定对象的行为。 例如,你可能想要找出为何对象插入到集合一次以上。 在 C# 和 F# 中,能够建立引用类型的特定实例的对象 ID,并在断点条件下使用它们。 对象 ID 由公共语言运行时 (CLR) 调试服务生成并与该对象关联。

建立对象 ID

一、设置断点在代码中的某个位置后建立对象。

二、开始调试,并在断点处暂停执行,选择调试 > Windows > 局部变量Alt+ 4以打开局部变量窗口。

      查找特定对象实例在局部变量窗口中,右键单击它,而后选择建立对象 ID

      应该会在“局部变量” $ 窗口中看到, 窗口中设置断点来中断调用函数返回到的指令或行处的执行。 这就是对象 ID。

展开名称,看到 $1 与 tri 对象彻底相同

以一样的方式给 rec、cir、shapes 对象分别建立对象ID,分别对应 $2  $3  $4 

三、在该对象添加到集合处, 右键单击该断点并选择“条件” 。

四、在“条件表达式”字段中使用对象 ID 。 例如,若是变量item是要添加到集合中,选择的对象为 true并键入item == $<n > ,其中<n > 的对象 ID 号.

     会在将该对象添加到集合中时中断执行。

tri 对象添加到集合处,设置条件为 tri == $1

rec 对象添加到集合处,设置条件为 rec == $2

 cir 对象添加到集合处,设置条件为 rec == $3

按下F5继续运行,

代码走到61行时,断点变成黄色箭头,鼠标悬浮在黄色箭头上,提示以下,条件表达式计算结果为 true。因此命中61行的断点。

按下F5继续运行,

代码走到62行时,断点变成黄色箭头,鼠标悬浮在黄色箭头上,提示以下,条件表达式计算结果为 true。因此命中62行的断点。

按下F5继续运行,

代码走到63行时,断点变成黄色箭头,鼠标悬浮在黄色箭头上,提示以下,条件表达式计算结果为 true。因此命中63行的断点。

 

 

若是将61行的条件设置为 tri == $2。根据上述的生成的对象ID,该表达式返回false。

再次F5,运行到61行时,提示报错。由于 tri 是 Triangle 类的对象,$2 是 Rectangle 类的对象建立的ID,因此没法进行 == 运算符的比较。调试器报错。

可是按下F5,仍然能够继续运行。

 

若是把61行的条件表达式修改成 tri.Equals($2),再次调试时,因为该表达式返回false,因此没有命中61行的断点。直接跳到62行。

 

     若要删除对象 ID,请右键单击中的变量局部变量窗口,而后选择删除对象 ID。

对象 ID 建立弱引用,且不会阻止对象被垃圾回收。 它们仅对当前调试会话有效。

命中次数

若是你怀疑你的代码中的循环开始产生错误行为在必定数量的迭代后,能够设置一个断点以中止执行的命中数,而无需重复按该数后F5来访问该迭代。

下列条件中断点设置窗口中,选择命中计数,而后指定迭代数。 在如下示例中,断点设置为其余每次迭代命中:

 F5调试,第一次 i = 0,不是 testInt 的2倍整数,因此没有命中74行的断点,直接跳到76行。

当 testInt的值为 二、四、1六、2二、46时,都能命中74行的断点。

 

筛选器

能够将断点限制为仅在指定设备上或在指定进程和线程中触发。

下条件中断点设置窗口中,选择筛选器,而后输入一个或多个如下表达式:

  • MachineName = "name"
  • ProcessId = value
  • ProcessName = "name"
  • ThreadId = value
  • ThreadName = "name"

将字符串值放在双引号内。 可使用 & (AND)、 || (OR)、 ! (NOT) 和括号合并子句。

提醒:断点条件 模式下进行调试,不能按F10,只能按F5进行调试才能看到实际效果。

08 断点操做和跟踪点

“跟踪点”是将消息打印到“输出”窗口的断点 。 跟踪点的做用像这种编程语言中的一个临时跟踪语句。

若要设置跟踪点:

  1. 右键单击断点并选择操做。 或者,在断点设置窗口中,悬停在所需断点,选择设置图标,,而后选择操做。

  2. 输入中的消息将消息记录到输出窗口字段。 消息能够包含通用文本字符串,值的变量或表达式括在大括号和格式说明符 ( C#  C++ ) 的值。

    此外能够在消息中使用如下特殊关键字:

    • $ADDRESS -当前指令
    • $CALLER -调用函数名
    • $CALLSTACK -调用堆栈
    • $FUNCTION -当前函数名
    • $PID -进程 id
    • $PNAME -进程名称
    • $TID -线程 id
    • $TNAME -线程名称
    • $TICK -选中计数 (从 Windows GetTickCount)
  3. 若要打印到的消息输出但不会中断,选择窗口继续执行复选框。 若要打印在跟踪点的消息和中断执行,请清除该复选框。

跟踪点显示为红色方块中的源代码的左边距和断点windows。

按下F5,运行结束后,查看【输出】窗口

09 断点警告

断点在调试时,有两个可能的可视状态: 一个实心的红色圆和 (白色填充) 空心圆。 若是调试器可以成功在目标进程中设置断点,它将保持一个实心的红色圆。 若是断点是空心圆,禁用断点,或尝试设置断点时出现警告。 若要肯定的不一样,断点上悬停并查看是否存在一条警告。

如下两个部分介绍重要警告以及如何解决这些问题。

“还没有为此文档加载任何符号”

转到模块窗口 (调试 > Windows > 模块) 并检查是否为你的模块加载。

 

  • 若是加载你的模块,则检查符号状态列,以查看是否已加载符号。

    • 若是还未加载符号,检查符号状态来诊断问题。 从上下文菜单中的模块上模块窗口中,单击符号加载信息... 若要查看其中调试器尝试并加载符号。 有关加载符号的详细信息,请参阅指定符号 (.pdb) 和源文件
    • 若是已加载符号,PDB 不包含有关源文件的信息。 如下是几个可能的缘由:
      • 若是最近添加的源文件,确认正在加载的模块的最新版本。
      • 能够建立使用去除的 Pdb /PDBSTRIPPED连接器选项。 去除的 Pdb 不包含源文件信息。 确认你正在使用完整 PDB 和不去除的 PDB。
      • PDB 文件部分已损坏。 删除文件,并执行干净的生成的模块来尝试解决此问题。
  • 若是你的模块未加载,请检查如下内容来查找缘由:

    • 确认您正在调试的正确过程。
    • 请检查你正在调试的代码正确的类型。 您能够了解哪一种代码将调试器配置为在调试进程窗口 (调试 > Windows > 进程)。 若是想要调试 C# 代码,例如,确认是否为适当类型的.NET Framework 配置您的调试器 (例如,托管 (v4*) 与托管 (v2*/v3*) 与托管 (CoreCLR))。

 

"… 当前源代码是从...中内置的版本不一样"

若是源文件已更改,而且源与正在调试的代码再也不匹配,调试器不会设置断点在代码中默认状况下。 一般状况下,此问题发生时更改源文件,但不从新生成的源代码。 若要解决此问题,从新生成项目。 若是生成系统认为该项目已是最新但没有,能够强制项目系统在从新生成经过再次保存源文件或经过清除项目的生成输出生成前。

在极少数状况下,你可能想要调试而无需匹配的源代码。 调试没有匹配的源代码能够使人混淆的潜在顾客调试体验,所以请确保这是你想要继续操做。

若要禁用这些安全检查,请执行如下操做:

  • 若要修改单个断点,请将鼠标悬停在编辑器中的断点图标,而后单击设置 (齿轮) 图标。 查看窗口添加到在编辑器中。 在查看窗口顶部,没有指示的断点的位置的超连接。 单击超连接,以容许修改的断点位置,而后检查容许源代码与原始不一样。
  • 若要修改此设置对全部断点,请转到调试 > 选项和设置。 在 “调试”/“常规” 页上,清除 “要求源文件与原始版本彻底匹配” 选项。 请务必从新启用此选项,在完成时调试。

 

10 断点已成功设置 (无警告),但未命中

本部分提供信息以对问题进行故障排除时调试器未显示任何警告 – 断点是一个实心的红色圆时主动进行调试,但未命中断点。

下面是要检查的几个事项:

  1. 若是在多个进程或多台计算机运行你的代码,请确保你正在调试的正确的进程或计算机。
  2. 确认你的代码正在运行。 若要测试你的代码运行,将调用添加到System.Diagnostics.Debugger.Break(C#/VB) 或__debugbreak(C++) 到在您尝试设置了断点,而后从新生成你的项目的代码行。
  3. 若是你正在调试优化的代码,请确保在其中设置断点的函数不被内联到另外一个函数。Debugger.Break如何工做的上一个检查中所述的测试,测试以及此问题。

 

11 删除了断点,但在再次启动调试时继续命中该断点
若是在调试时删除了断点,可能在下一步启动调试的时再次命中该断点。 要中止命中此断点,请确保从 “断点” 窗口删除该断点的全部实例。
相关文章
相关标签/搜索