所以,经过一周处理一个真正的巫毒错误(已经解决了,当然,通过在相关位置添加一个#include
),我意识到一个人不应该总是信任调试器,如果有些东西没有意义,好的printf()
可能对你有用。
据我所知,如果在发布模式下编译代码,调试器可能会“撒谎”。我最近了解到,如果一个班级有#ifdef
,那就像
struct MyStruct
{
char a;
#ifdef USE_ME
double c;
#else
int c;
#endif
};
并且USE_ME
没有在结构定义可见的标题中定义,但是在其他地方定义,而不是调试器混淆,因为它不知道c是什么类型并且将“撒谎”,即使我们处于调试模式。
我的问题是:任何人都可以给出调试器何时会出现的其他情况吗?
答案 0 :(得分:4)
调试器通常不会说谎(除非它有问题)。它会告诉您程序中到底发生了什么。您的问题是,您的程序中发生的事情与您在程序中思考的情况不同 - 或者与您在源代码中编写的内容不同。
当编译器优化代码时(例如,当您构建发布版本时),它会以多种方式转换代码,这意味着操作将被重新排序或完全删除。
调试时,调试器会尽力将发生的事情与源代码中的内容相关联,但它不能完美地完成,只是因为编译器可能选择了完全不同的方法来实现相同的目标。因此,您经常会看到调试器中根本看不到变量(它们已被优化),或者它们具有意外值,或者您将看到调试器在不同源代码行之间看似随机跳转。
所以调试器不会说谎。它只是告诉你一个与你预期不同的真相。它告诉你程序中实际发生的事情的真相 - 而不是源代码中所写内容的“真相”。
答案 1 :(得分:1)
一个典型的谎言例子是内存损坏(堆栈或堆损坏),以及一般与内存相关的问题(例如悬挂引用)。
这是调用未定义行为的一个结果,即使在这种情况下调试器的行为未定义,因为调试器正在使用无效的编译代码。
调试器善于帮助解决格式错误的程序中的逻辑问题,并且可以帮助发现错误的程序中的一些错误(例如null解除引用);但并非所有类型的格式错误的程序都可以进行有效调试。当然,在多线程程序(以及其他程序)中,事情变得更加激烈,因为观察程序的事实改变了它的行为......
答案 2 :(得分:0)
调试器可以分为两种情况: