调试器什么时候会撒谎

When would a debugger lie?

本文关键字:什么时候 调试器      更新时间:2023-10-16

所以,在处理了一个真正的巫毒教错误一周后(解决了,但当然,通过在相关位置添加一个#include),我意识到人们不应该总是相信调试器,如果有什么事情没有意义,好的旧printf()可能对你有用。据我所知,如果代码在发布模式下编译,调试器可能会"撒谎"。我最近了解到,如果一个班级有一个#ifdef,比如

struct MyStruct
{
    char a;
#ifdef USE_ME
    double c;
#else
    int c;
#endif
};

并且USE_ME不是在结构定义可见的标头中定义的,而是在其他地方定义的,因为调试器会感到困惑,因为它不知道 C 类型是什么并且会"撒谎",即使我们处于调试模式。我的问题是:任何人都可以给出调试器何时撒谎的其他情况吗?

调试器通常不会撒谎(除非它有问题)。它准确地告诉您程序中发生了什么。你的问题是,你的程序中发生的事情与你认为的程序中发生的事情不同 - 或者与你在源代码中编写的内容不同。

当编译器优化代码时(例如,在生成发布版本时),它会以多种方式转换代码,这意味着操作将被重新排序或完全删除。

调试时,调试器会尽力将正在发生的事情与源代码中编写的内容相关联,但它不能完美地做到这一点,这仅仅是因为编译器可能选择了完全不同的方式来实现相同的目标。因此,您经常会看到变量在调试器中根本看不到(它们已被优化),或者它们具有意外的值,或者您会看到调试器似乎随机地在不同的源代码行之间跳转。

所以调试器不会说谎。它只是告诉你一个与你期望看到的不同真相。它告诉你程序中实际发生的事情的真相 - 而不是源代码中编写的"真相"。

谎言的一个典型例子发生在内存损坏(堆栈或堆损坏)和一般内存相关问题(例如悬空引用)中。

这是调用未定义行为的一个结果,在这种情况下,即使调试器的行为也是未定义的,因为调试器正在使用无效的编译代码。

调试

器擅长帮助解决格式良好的程序中的逻辑问题,并且可以帮助发现格式错误的程序中的一些错误(例如空取消引用);但并非所有类格式错误的程序都可以有效地调试。当然,在多线程程序(以及其他程序)中,事情变得更加毛茸茸,因为观察程序的事实会改变它的行为......

调试器可以在两种情况下:

  1. 您正在使用缺失/不正确的符号(包括您的符号和操作系统的符号)进行调试。
  2. 你的构建很糟糕。 也许有些陈旧.OBJ被链接了,而不是首先被重建。 这有时会发生在大型项目/解决方案上,特别是如果您使用"老式"的方式来指定项目依赖项,而不是VS2010的官方方式。