Visual C++ - 为什么要使用调试模式?

3

我刚刚按照启用Release模式下的调试符号的建议去做了,启用调试符号后禁用优化,发现如果使用Release模式编译符号,则断点可以正常工作,这让我想到...

  1. Debug模式的目的不是帮助你找到bug吗?
  2. 如果Debug模式会让bug漏掉,那还有什么意义呢?

请问您有什么建议吗?


你是什么意思,"如果它让漏洞溜过去了"?它怎么做到的? - jalf
调试模式初始化未初始化的变量,并像链接的文章中那样在数组等周围设置保护。 - Extrakun
7个回答

16

实际上,不存在所谓的“发布模式”或“调试模式”,只有不同的配置和不同的选项启用。 “发布模式”和“调试模式”只是常见的配置。

你所做的是修改发布配置以启用通常在调试配置中启用的某些选项。

启用这些选项会使二进制文件变得更大且更慢,具体取决于您启用的选项。

启用的选项越多,查找错误就越容易。我认为你的问题应该是“为什么要使用发布模式?”答案是它更小更快。


8

调试模式不会“让漏洞溜过你”。它插入检查以捕获大量的漏洞,但这些检查的存在也可能隐藏某些其他漏洞。所有错误检查代码都可以捕获很多错误,但它也作为填充物,并可能隐藏微妙的边界错误。

因此,这本身就足以运行两者了。MSVC在调试模式下执行大量的附加错误检查。

此外,许多调试工具,例如assert依赖于未定义NDEBUG,这是调试构建中的情况,但默认情况下不适用于发布构建。


3

优化将被关闭,这样调试更容易(否则代码可能会以奇怪的方式重新排序)。此外,条件代码,如assert()等,也可以包含在内。


3
除了你的应用程序在发布模式下易于调试之外,MSVC运行时库以及其他一些库并不那么友好。例如,调试堆会在分配的内存周围添加无人区标记以捕获缓冲区溢出。MSVC使用的标准库会为迭代器有效性进行断言检查,还有更多类似的限制。

1

由于优化器而导致的错误并不罕见;但通常它们暗示着更深层次的问题,例如,在需要使用volatile时没有使用会导致优化器错误(优化比较并使用缓存结果)。

归根结底,在早期版本中包含调试符号可以帮助您在部署后跟踪错误。

现在,直接回答您的问题:

  1. 调试模式还有其他东西,如在发布模式中被剥离的assert()
  2. 即使您在发布模式下进行所有测试,仍然会有错误漏掉。事实上,一些错误(如上述的volatile错误)只在调试模式下隐藏:它们仍然存在,只是更难触发。

1

在应用程序中包含完整符号,可以包含有关构建机器的重要信息(路径等嵌入其中)。

建议在发布版本中使用“仅PDB”符号(不包括文件、行和本地变量符号),并开启优化。而调试版本没有优化和完整符号。

如其他答案所述,公共子表达式消除和指令重排序可能会使调试变得有趣(移动到下一行时,会跳转到n、n+2、n+1行...)。


0

优化对于调试来说是一场噩梦。我曾经有一个应用程序,其中包含了这个for循环。

for (int i = 0; i < 10; i++)
{
  //use i with something
}

在调试中,我一直是0。但将其输出到控制台后发现它确实增加了。


如果你只是打印它,那么很可能为变量分配了内存,但从未使用过,而是更喜欢在寄存器中缓存“i”。这有点诡异。 - Matthew Scharley
你要找的单词是“优化”,而不是“optimalisation”。 :) - jalf

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接