【问题标题】:Differences between running an executable with Visual Studio debugger vs without debugger使用 Visual Studio 调试器与不使用调试器运行可执行文件之间的差异
【发布时间】:2013-05-17 18:44:32
【问题描述】:

我正在尝试调试一个问题,即当直接从 Visual Studio 执行时,可执行文件会产生可重复的输出(我想要的),但从命令提示符执行时会产生可重复的输出。这是一个单线程应用程序,因此在时间方面不应该有任何奇怪的行为。

有人能列举出这两种环境之间可能存在的差异吗?

我确定实际的可执行文件是相同的——它们都是发布版本并且运行相同的 .exe 文件。

这里是环境和结果:

  1. 直接从命令提示符 (cmd) 运行:不可重复输出
  2. 通过调试 (F5) 从 Visual Studio 运行:可重复输出
  3. 从 Visual Studio 运行而不进行调试 (Ctrl-F5):不可重复的输出

我知道工作目录可能不同,但我正在手动调整它以确保工作目录相同。

根据这些结果,看起来运行“带调试”(即使在发布版本中)以某种方式解决了问题。这是否指向一个可能的罪魁祸首?运行带调试和不带调试的可执行文件有什么区别?

解决方案: 正如接受的答案中所指出的,调试堆是问题所在。问题是在我们代码的深处,有人在初始化之前访问了一个大数组的一部分。他们已经用 malloc 分配了内存并且没有将内存初始化为 0。调试堆(我假设)会用一些可重复的值填充数组,而当没有附加调试器时(即从命令行运行或使用Ctrl-F5)这些值更加随机,有时会导致程序行为的微小偏差。不幸的是,调整是如此微妙以至于几乎无法察觉,并且在处理的第一个“帧”之后,有问题的内存被正确重置,但初始条件已经略有不同,损坏已经完毕。混沌理论在行动!感谢您的指导。

一个很有帮助的调试技巧:编写一个自定义 malloc,立即用完全随机的数据填充内存。这样,您可以确保在使用它之前自己正确初始化它,否则每次运行它时您的结果都会(希望)很疯狂——即使在调试模式下使用调试堆!

【问题讨论】:

  • 取决于您的代码。您可能会触发未定义的行为,只会在更高的优化级别出现。
  • 但理论上不是没有附加调试器的唯一区别?构建是相同的——两次发布构建。优化程度没有改变。
  • 我知道你说你正在调整工作目录,但这似乎是罪魁祸首。我要寻找的另一个问题是安装的库。 VS 处理依赖项(如果你通过 ClickOnce 构建和安装,它会处理你的依赖项),但直接在命令行上运行可能不会。
  • 我的 VS 生锈了,您确定它运行的是相同的发布可执行文件(而不是调试版本)吗?链接库呢?
  • 看来我的问题标题实际上不太准确 - 只需以两种不同的方式运行应用程序即可重现该问题。如果我用 F5 运行,我会得到我想要的结果。如果我使用 Ctrl-F5 运行,我不会得到我想要的结果。所以似乎与附加调试器相关的东西会改变可执行文件的行为。这应该消除工作目录和链接库的问题,不是吗?

标签: c++ windows visual-studio-2010 visual-studio


【解决方案1】:

Windows Heap behaves differently if process is started under the debugger. 要禁用此行为(以便在调试时发现问题)添加 _NO_DEBUG_HEAP=1 到环境中(如在this question 中)。

或者,您可以在程序执行的早期附加到进程。 Heap 将不会进入调试模式。在执行开始的某处添加DebugBreak() 行,使用Ctrl+F5 运行,并在被要求时开始调试。

【讨论】:

  • 那里也添加了很棒的链接。这对我来说似乎是一个很可能的问题——当附加调试器时,某种标记值是可重复的,但在其他情况下只是垃圾数据(因此是不可重复的行为!)
  • 这为我指明了正确的方向。我将用一些细节编辑问题。谢谢!
【解决方案2】:

好吧,如果不了解您的代码,就很难说。但是,我在执行大量浮点运算(双精度数)的程序时遇到了类似的问题。

当我处理的数字略有不同但机器在数字上无法区分时,问题就会出现。 如果两个双精度数的差异小于numeric_limits<double>::epsilon(),则它们被视为机器的相同数字。因此,类型的表达式:

if (num1==num2)...

if (num1<num2)...
...

可以产生五颜六色的效果。

在调试或发布模式下运行时,这些彩色效果会有所不同。原因是调试/发布运行时库不同。此外,至关重要的是,编译是通过不同的代码优化完成的。命令行调试版本和调试窗口版本 (F5) 之间的差异也可以通过细微的优化差异来解释。

如果您使用的是 VS,您可以在 Properties 菜单的 C/C++Linker 部分查看不同编译选项和优化的效果。

为避免此问题,我建议使用&lt;limits&gt; STL 库中的numeric_limits 工具。例如,小于运算符的实现应该是这样的:

bool operator<(double num1, double num2) {
    double difference=fabs(num1-num2);
    if (difference>numeric_limits<double>::epsilon()) {
        if (num1 < num2) return true;
        return false;
    }
    return false;
}

【讨论】:

    猜你喜欢
    • 2011-11-27
    • 2011-08-19
    • 1970-01-01
    • 1970-01-01
    • 2019-10-31
    • 1970-01-01
    • 1970-01-01
    • 2011-04-21
    • 1970-01-01
    相关资源
    最近更新 更多