调试器什么时候会撒谎
When would a debugger lie?
所以,在处理了一个真正的巫毒教错误一周后(解决了,但当然,通过在相关位置添加一个#include
),我意识到人们不应该总是相信调试器,如果有什么事情没有意义,好的旧printf()
可能对你有用。据我所知,如果代码在发布模式下编译,调试器可能会"撒谎"。我最近了解到,如果一个班级有一个#ifdef
,比如
struct MyStruct
{
char a;
#ifdef USE_ME
double c;
#else
int c;
#endif
};
并且USE_ME
不是在结构定义可见的标头中定义的,而是在其他地方定义的,因为调试器会感到困惑,因为它不知道 C 类型是什么并且会"撒谎",即使我们处于调试模式。我的问题是:任何人都可以给出调试器何时撒谎的其他情况吗?
调试器通常不会撒谎(除非它有问题)。它准确地告诉您程序中发生了什么。你的问题是,你的程序中发生的事情与你认为的程序中发生的事情不同 - 或者与你在源代码中编写的内容不同。
当编译器优化代码时(例如,在生成发布版本时),它会以多种方式转换代码,这意味着操作将被重新排序或完全删除。
调试时,调试器会尽力将正在发生的事情与源代码中编写的内容相关联,但它不能完美地做到这一点,这仅仅是因为编译器可能选择了完全不同的方式来实现相同的目标。因此,您经常会看到变量在调试器中根本看不到(它们已被优化),或者它们具有意外的值,或者您会看到调试器似乎随机地在不同的源代码行之间跳转。
所以调试器不会说谎。它只是告诉你一个与你期望看到的不同真相。它告诉你程序中实际发生的事情的真相 - 而不是源代码中编写的"真相"。
谎言的一个典型例子发生在内存损坏(堆栈或堆损坏)和一般内存相关问题(例如悬空引用)中。
这是调用未定义行为的一个结果,在这种情况下,即使调试器的行为也是未定义的,因为调试器正在使用无效的编译代码。
调试器擅长帮助解决格式良好的程序中的逻辑问题,并且可以帮助发现格式错误的程序中的一些错误(例如空取消引用);但并非所有类格式错误的程序都可以有效地调试。当然,在多线程程序(以及其他程序)中,事情变得更加毛茸茸,因为观察程序的事实会改变它的行为......
调试器可以在两种情况下:
- 您正在使用缺失/不正确的符号(包括您的符号和操作系统的符号)进行调试。
- 你的构建很糟糕。 也许有些陈旧.OBJ被链接了,而不是首先被重建。 这有时会发生在大型项目/解决方案上,特别是如果您使用"老式"的方式来指定项目依赖项,而不是VS2010的官方方式。
- 什么时候调用组成单元对象的析构函数
- 什么时候在C++中返回常量引用是个好主意
- 什么时候调用析构函数
- 正在VS调试器中监视映射条目
- boost odeint什么时候真正调用观测者
- 编译器对数组声明大小的计算。什么时候发生?
- 什么时候最好在子进程中使用 CPU 或 I/O 密集型代码 [ C++ ]
- 您应该在什么时候创建自己的异常类型
- 为什么我的 VS 代码调试器在我的C++代码周围弹跳?
- 我什么时候会默认(而不是删除)基类中的复制和移动操作
- 带有 GDB 调试器的 VS 代码内存视图
- 什么时候足以将const_iterator声明为const迭代器
- 在内部和外部与调试器之间运行有什么区别
- 如何配置Qt调试器以及它的工作需要什么
- 野牛解析器:我什么时候需要'return',什么时候不需要?
- 调试器什么时候会撒谎
- 这些 valgrind/GNU 调试器错误消息是什么意思
- <A> 如果 A 有析构函数,std::unique_ptr 什么时候需要特殊的删除器?
- 什么调试器可以检查c++代码是否存在内存泄漏
- c++什么是一个很好的分段错误调试器