Ben*_*oit 12 c c++ compiler-construction
在大多数C或C++环境中,存在"调试"模式和"释放"模式编译.
看看两者之间的区别,您会发现调试模式添加了调试符号(通常是许多编译器上的-g选项),但它也会禁用大多数优化.
在"发布"模式下,您通常会启用各种优化.
为什么不同?
Ben*_*oit 28
没有任何优化,代码流是线性的.如果您在第5行并且单步执行,则跳到第6行.通过优化,您可以获得指令重新排序,循环展开和各种优化.
例如:
void foo() {
1: int i;
2: for(i = 0; i < 2; )
3: i++;
4: return;
Run Code Online (Sandbox Code Playgroud)
在这个例子中,没有优化,你可以单步执行代码并点击第1,2,3,2,3,2,4行
通过优化,您可能会获得如下所示的执行路径:2,3,3,4甚至只需4!(该功能毕竟不做任何事......)
最重要的是,启用优化的调试代码可能是一个巨大的痛苦!特别是如果你有大功能.
请注意,启用优化会更改代码!在某些环境(安全关键系统)中,这是不可接受的,正在调试的代码必须是发送的代码.在这种情况下需要进行优化调试.
虽然优化和非优化代码应该在"功能上"等效,但在某些情况下,行为会发生变化.
这是一个简单的例子:
int* ptr = 0xdeadbeef; // some address to memory-mapped I/O device
*ptr = 0; // setup hardware device
while(*ptr == 1) { // loop until hardware device is done
// do something
}
优化关闭,这很简单,你知道会发生什么.但是,如果您打开优化,可能会发生以下几种情况:
在所有这些情况下,行为将完全不同,很可能是错误的.
调试和发布之间的另一个重要区别是局部变量的存储方式。从概念上讲,局部变量在函数堆栈帧中分配存储空间。编译器生成的符号文件告诉调试器变量在堆栈帧中的偏移量,以便调试器可以显示给你。调试器通过查看内存位置来执行此操作。
但是,这意味着每次更改局部变量时,该源代码行的生成代码都必须将值写回堆栈上的正确位置。由于内存开销,这非常低效。
在发布版本中,编译器可以将局部变量分配给函数的一部分的寄存器。在某些情况下,它可能根本不为其分配堆栈存储(机器拥有的寄存器越多,这样做就越容易)。
但是,调试器不知道寄存器如何映射到代码中特定点的局部变量(我不知道包含此信息的任何符号格式),因此它无法准确地向您显示它,因为它没有不知道去哪里找。
另一个优化是函数内联。在优化构建中,编译器可能会在任何使用它的地方用 foo 的实际代码替换对 foo() 的调用,因为该函数足够小。但是,当您尝试在 foo() 上设置断点时,调试器想要知道 foo() 指令的地址,对此不再有简单的答案——可能有数千个 foo() 副本) 代码字节分布在您的程序中。调试版本将保证您可以在某个地方放置断点。
| 归档时间: |
|
| 查看次数: |
3225 次 |
| 最近记录: |