【问题标题】:Possible break point issue with Visual Studio 2012 RC?Visual Studio 2012 RC 可能出现断点问题?
【发布时间】:2012-08-06 06:26:25
【问题描述】:

在使用 Visual Studio 2012 RC 调试一些 C++ 代码时,我注意到在类成员函数和成员变量值上有断点的奇怪行为。

当我在类成员函数上设置断点时,VS 2012 将断点放在函数大括号上。现在,当悬停在函数使用的成员变量上时,该值始终“未初始化”。但是,按 F10 进入下一行(函数中的第一行),成员变量现在更改为正确的值。

这看起来像一个类的成员变量的值直到进入成员函数的第一行才被加载。但这很令人困惑——那么打破大括号的意义何在? (在函数上设置断点时的默认设置。)

打破类成员函数:

成员变量active 据说是true(实际上不是!)

按 F10 进入下一行:

成员变量active 现在被称为false(这是正确的。)

我在这里遗漏了什么还是这是 Visual Studio 2012 RC 中的实际错误?

编辑: 我找到了我的 Visual Studio 2010 副本并尝试了这个。关于断点的行为是相同的。不同之处在于 IntelliSense 如何处理这种情况。在 VS 2010 中,IntelliSense 在大括号上断开时根本不会弹出工具提示,而在 VS 2012 中始终显示工具提示。我认为 VS 2010 的行为要好得多,可以避免混淆。

【问题讨论】:

  • Visual Studio 2010 是否表现出相同的调试器行为?
  • @JamesMcNellis 我没有 Visual Studio 2010。抱歉。
  • 我也没有安装它了。我一直认为这要么是设计的,要么是一个怪癖。基本上,当调试器在{ 上中断时,this 指针尚未初始化。
  • 如果这是设计使然,那什么时候有用?
  • @JamesMcNellis 仅供参考:我用 VS 2010 的行为更新了我的问题

标签: visual-studio visual-studio-2012


【解决方案1】:

通过在花括号上设置断点,您可以让调试器在硬地和硬地之间进行选择。一个难点是编码风格约定,你喜欢 K&R 支撑吗?

void foo() {
   // etc..
}

你如何在那个上设置断点?出于安全考虑,调试器会出错,它会在函数入口点设置断点。当您的断点命中时,您可以使用 Debug + Windows + Assembly,您会发现它在函数中的第一条机器代码指令上设置了断点。几乎总是push ebp。这实际上与调试器尝试处理模糊断点的正常方式有点不同,它通常向前看,而不是向后看。所以这是非常刻意的。在托管代码的调试器中解决的问题不仅是基于行的,而且还关注列。这并没有流回 C++ 调试器,它仍然是基于行的。

所以检查局部变量不会很好,没有。直到执行设置堆栈帧的函数序言。包括这个

调试器向后看而不是像往常那样向前看的可能原因是您希望单步执行作为局部变量的类对象的构造函数。同样,除了自己倒回堆栈并在构造函数上设置断点之外,您无法设置明确的断点。谁知道在哪里。

功能,而不是错误。显而易见的解决方法是在函数体的第一条语句上设置断点。到那时一切都设置好了,堆栈帧以及局部变量。

【讨论】:

  • 我同意这是一项功能,而不是错误。不过,我仍然认为这是 IntelliSense 的一个问题。它至少应该在视觉上表明它不能确定变量的值。
  • IntelliSense 与调试器无关。你必须通过至少 4 或 5 个管理级别才能在微软找到一个共同的老板。调试器运行良好的原因之一。
  • 有趣。作为记录,我更新了我的问题,以突出显示 IntelliSense 与 VS 2010 和 VS 2012 的不同行为。由于我的问题涉及断点和调试器,我将接受此作为最佳答案。
【解决方案2】:

默认情况下,在 x86 上,C++ 成员函数使用 thiscall 调用约定(*),它通过 ecx 寄存器传递 this 指针。不过,该函数可以使用此寄存器进行计算,因此调试器不能在函数执行的整个过程中依赖其值作为 this 指针。

因此,在未优化的构建中,作为在进入函数主体之前执行的函数序言的一部分,this 指针将“溢出”到堆栈:它被复制到堆栈,以便调试器可以可靠地获取其值。当您观看this 或成员变量(通过this 指针隐式访问)时,调试器使用的是this 指针的副本。

当您在{ 的左大括号上放置断点时,断点将放置在函数序言的初始地址处,即在调用函数时将执行的第一条指令处。只有在你跨过这个左大括号之后,函数序言才会执行,this 指针才会溢出到堆栈中。

如果您需要通过函数序言进行调试,这会很有用。如果您逐步完成反汇编(调试 -> Windows -> 反汇编),会发生什么情况会更加明显。


(*) 在 x64 上,只有一个调用约定,是 fastcall 调用约定。 this 指针最终将通过 rcx 寄存器传递,因为它是函数的“第一个”参数。

在 x86 上,并非所有成员函数都使用 thiscall 调用约定,它只是默认值。与其他函数类型一样,您可以指定函数的调用约定。例如,对使用 stdcall 调用约定的 COM 组件执行此操作。

【讨论】:

  • 这是有道理的。我想这更多是 IntelliSense 的问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-03-27
  • 2015-10-31
  • 2018-01-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多