调试优化代码

本文介绍需要设置哪些编译器选项来更好地调试优化后的代码。

从 Visual Studio 2022 版本 17.14 开始,可以使用更好的体验来调试优化代码,就像它是未优化编译一样,同时保持优化代码的速度。 有关详细信息,请参阅 C++动态调试(预览版)

注释

你看到的对话框和菜单命令可能与“帮助”中所述的命令不同,具体取决于你的活动设置或版本。 若要更改设置,请选择 “工具”菜单上的“导入和导出设置”。 有关详细信息,请参阅重置所有设置

注释

/Zo(增强优化调试) 编译器选项(Visual Studio Update 3 中引入)为优化代码(未使用 /Od 编译器选项生成的项目)生成更丰富的调试信息。 请参阅 /O 选项(优化代码))。 这包括对调试局部变量和内联函数的改进支持。

当使用 /Zo 编译器选项时,编辑并继续会被禁用。

当编译器优化代码时,它会重新定位并重新组织指令。 这会导致更高效的编译代码。 由于这种重新排列,调试器不能始终标识与一组指令相对应的源代码。

优化可能会影响:

  • 优化器可以删除局部变量,或将其移动到调试器无法理解的位置。

  • 函数内的位置,当优化器合并代码块时,这些位置会被更改。

  • 调用堆栈上框架的函数名称(如果优化器合并两个函数,则函数名称可能是错误的)。

    但是,假定所有框架都有符号,则在调用堆栈上看到的框架几乎总是正确的。 如果堆栈损坏,如果有用汇编语言编写的函数,或者调用堆栈上存在没有匹配符号的操作系统帧,则调用堆栈上的帧可能会错误。

    全局变量和静态变量始终正确显示。 结构布局也是如此。 如果你有指向结构的指针且指针的值正确,则结构的每个成员变量将显示正确的值。

    由于这些限制,应尽可能使用程序未优化的版本进行调试。 默认情况下,优化在C++程序的调试配置中处于关闭状态,并在“发布”配置中打开。

    但是,bug 可能仅出现在程序的优化版本中。 在这种情况下,必须调试优化的代码。

在“Debug”生成配置中打开优化

  1. 创建新项目时,选择 Win32 Debug 目标。 接下来要一直使用 Win32 Debug 目标,直至程序已进行全面调试并可以生成 Win32 Release 目标为止。 编译器不会优化 Win32 Debug 目标。

  2. 在解决方案资源管理器中选择项目。

  3. 在“视图”菜单上,单击“属性页”

  4. 在“属性页”对话框中,确保在 配置 下拉列表中选择 Debug

  5. 在左侧的文件夹视图中,选择 C/C++ 文件夹。

  6. C++ 文件夹下,选择 Optimization

  7. 在右侧的属性列表中,找到 Optimization。 它旁边的设置可能显示为 Disabled (/Od)。 选择其他选项之一(Minimum Size``(/O1)Maximum Speed``(/O2)Full Optimization``(/Ox)Custom)。

  8. 如果选择 OptimizationCustom 选项,现在可以为属性列表中显示的任何其他属性设置选项。

  9. 选择项目属性页的配置属性、C/C++、命令行节点,并将 (/Zo) 添加到 其他选项 文本框中。

    警告

    添加 /Zo 会禁用编辑并继续

    调试优化代码时,请使用 反汇编 窗口查看创建和执行的说明。 设置断点时,需要知道断点可能与指令一起移动。 例如,请考虑以下代码:

for (x=0; x<10; x++)

假定在该行设置了一个断点。 你可能希望断点命中 10 次,但如果代码已优化,则断点只命中一次。 这是因为第一个指令将 x 的值设置为 0。 编译器认识到,这只需完成一次,并将其移出循环。 断点随之移动。 比较和递增 x 的指令仍保留在循环中。 查看“反汇编”窗口时,单步执行单元自动设置为“指令”以增强控制,这在逐句通过优化的代码时很有用