为什么在调试应用程序时有必要/建议关闭所有编译器优化?
背景
我正在使用 8 位微控制器 (OKI 411),它具有 15K 可用代码存储空间,用于中断服务例程 + ROM 区域/窗口(常量全局变量)+ 代码。我们几乎消耗了约 13K,因此在甚至调试期间打开最大可能的优化是非常诱人的。
编译调试二进制文件时,编译器尝试在代码语句(或代码语句片段)与汇编语言指令之间保持 1:1 对应关系。 这样,当您进行调试时,您可以逐条指令地执行,并且调试器可以轻松地将其在二进制文件中的当前位置与正确的源代码关联起来。 通常编译器还会确保所有命名变量实际上存在于内存中的某个位置,以便您可以在调试器中查看它们的内容。
编译器优化可能会消除未使用或不必要的局部变量,并可能重组您的代码以使其更加高效。 函数可以内联,并且表达式可以部分或全部预先计算或重新排列。 大多数这些和类似的优化使得很难将原始源代码与生成的程序集关联起来。
考虑:
for (i = 0; i < 10; i++) {
src[i] = dest[i];
}
优化后,这段代码可能看起来像:
src[0] = dest[0];
src[1] = dest[1];
⋮
src[9] = dest[9];
换句话说,不再有
i
了。调试器期望 i
位于堆栈帧上,但优化器将其删除。
此外,当单步执行时,PC会到处跳转(显然是随机的),并且你会遇到各种其他奇怪的情况,这将使调试变得非常困难或不可能(取决于优化器做了什么)。
打开就可以了。 它通常是关闭的,因为它使编译速度更快,这对于大型项目来说可能是一个真正值得关注的问题。 如果可以的话,实际上最好打开它,这样你就不会因为最后一刻的优化而遇到任何讨厌的问题。
就你而言,我肯定会打开它。
这可能会导致某些形式的调试出现问题,但在这些情况下您应该能够将其关闭。
我遇到了类似的情况,我试图从硬件寄存器中读取数据,该寄存器是内存映射的,它在 gcc 中给了我错误的 CFLAGS="-o2" 值。但是,当我打开 CFLAGS="- O0”,它开始工作。可能值得一提的是,通过将其转换为易失性变量可以实现相同的结果,从而绕过编译器优化。
我唯一能想到的是这可能会让调试变得更加困难。
除此之外应该没有什么问题了。