调试模式中不存在发布版本中的错误的常见原因

时间:2009-11-19 09:46:43

标签: c++ release-mode debug-mode

错误和异常程序行为的典型原因是什么只在发布编译模式中表现出来但在调试模式下不会发生?

18 个答案:

答案 0 :(得分:30)

很多时候,在C ++的调试模式下,所有变量都是空的初始化,而除非明确说明,否则在发布模式下不会发生同样的变化。

检查是否有任何调试宏和未初始化的变量

您的程序是否使用线程,然后优化也会在发布模式下导致一些问题。

同时检查所有异常,例如与发布模式没有直接关系,但有时我们会忽略一些关键异常,例如VC ++中的mem访问冲突,但至少在Linux,Solaris等其他操作系统中也是如此。理想情况下,您的程序不应该捕获诸如访问NULL指针之类的关键异常。

答案 1 :(得分:19)

常见的陷阱是在ASSERT中使用带副作用的表达式。

答案 2 :(得分:9)

其他差异可能是:

  • 在垃圾收集语言中, 收藏家通常更具侵略性 在发布模式下;
  • 内存布局可以 经常是不同的;
  • 记忆可能是 初始化不同(例如可能是 在调试模式下归零,或重复使用更多 积极地发布);
  • 当地人可以 被提升为在发布中注册值,可以 引起浮点问题 值。

答案 3 :(得分:6)

我曾经被一些错误所困扰,这些错误在Debug版本中很好但在Release版本中崩溃了。有许多根本原因(当然包括那些已经在这个帖子中总结的原因)并且我已经被以下所有因素所困扰:

  • #ifdef _DEBUG中的成员变量或成员函数,因此在调试版本中类的大小不同。有时在发布版本中使用#ifndef NDEBUG
  • 同样地,有一个不同的#ifdef碰巧只出现在两个版本之一中
  • 调试版本使用系统库的调试版本,尤其是堆和内存分配函数
  • 发布版本中的内联函数
  • 包含头文件的顺序。这不应该导致问题,但如果你有一些像#pragma pack这样的东西没有被重置,那么这可能会导致令人讨厌的问题。使用预编译头和强制包含
  • 也会发生类似问题
  • 缓存:您可能拥有仅在发布版本中使用的缓存等代码,或者不同的缓存大小限制
  • 项目配置:调试和发布配置可能有不同的构建设置(使用IDE时可能会发生这种情况)
  • 由于仅调试代码而导致的竞争条件,时间问题和错误的副作用

我多年来积累的一些提示,用于深入了解调试/发布错误:

  • 尝试在调试版本中重现异常行为,如果可以,甚至更好,编写单元测试来捕获它
  • 考虑两者之间的区别:编译器设置,缓存,仅调试代码。尽量暂时尽量减少这些差异
  • 创建一个发布版本,关闭优化(因此您更有可能在调试器中获得有用的数据)或优化的调试版本。通过最小化调试和发布之间的更改,您更有可能找出导致错误的差异。

答案 4 :(得分:3)

是的!,如果你有条件编译,可能会有时间错误(优化的发行代码,非优化的调试代码),内存重用与调试堆。

答案 5 :(得分:3)

它可以,特别是如果你在C领域。

一个原因可能是DEBUG版本可能会添加代码以检查杂散指针并以某种方式保护您的代码不会崩溃(或行为不正确)。如果是这种情况,您应该仔细检查从编译器获得的警告和其他消息。

另一个原因可能是优化(通常用于发布版本,关闭用于调试)。代码和数据布局可能已经过优化,而您的调试程序只是访问未使用的内存,发布版本现在尝试访问保留的内存甚至指向代码!

编辑:我看到其他人提到了它:当然,如果不在DEBUG模式下编译,你可能会有条件地排除整个代码段。如果是这样的话,我希望这真的是调试代码而不是对程序本身的正确性至关重要的东西!

答案 6 :(得分:3)

CRT库函数在调试与发布(/ MD vs / MDd)中表现不同。

例如,调试版本通常预填充您传递到指定长度的缓冲区以验证您的声明。示例包括strcpy_sStringCchCopy等。即使字符串提前终止,您的 szDest 也最好 n 字节!

答案 7 :(得分:2)

当然,例如,如果你使用像

这样的结构
#if DEBUG

//some code

#endif

答案 8 :(得分:2)

在.NET中,即使您不使用#if DEBUG之类的条件编译,编译器在发布模式下的优化仍然比在调试模式下更加自由,这可能导致仅释放错误好。

答案 9 :(得分:1)

如果没有更多细节,我会假设“不行”意味着它要么在运行时不编译或抛出某种错误。通过#if DEBUG语句或标有Conditional属性的方法检查您是否拥有依赖于编译版本的代码。

答案 10 :(得分:1)

你需要提供更多信息,但是,这是可能的。这取决于您的调试版本。您可能正在进行日志记录或额外检查,但不会将其编译为发行版本。这些仅调试的代码路径可能具有意外的副作用,这些副作用会以奇怪的方式改变状态或影响变量。调试版本通常运行较慢,因此这可能会影响线程并隐藏竞争条件。对于发布编译的直接优化也是如此,尽管不太可能(尽管不太可能)发布编译可能会将某些内容短路作为优化。

答案 11 :(得分:1)

可能会破坏有效代码的编译器优化,因为它们过于激进。

尝试使用较少的优化功能编译代码。

答案 12 :(得分:1)

如果您有条件编译以使调试代码和发布代码不同,那么这是可能的,并且代码中存在仅在发布模式下使用的错误。

除此之外,这是不可能的。调试代码和发布代码的编译方式有所不同,如果在调试器下运行代码的执行方式不同,但如果这些差异中的任何差异导致性能差异以外的任何问题,则问题一直存在。< / p>

在调试版本中可能没有出现错误(因为时序或内存分配不同),但这并不意味着错误不存在。可能还有其他与调试模式无关的因素会改变代码的时序,导致错误发生或不发生,但这一切都归结为如果代码正确,则不会发生错误在任何情况下。

所以,不,调试版本不正常只是因为你可以运行它而不会出错。如果在发布模式下运行时发生错误,则不是因为发布模式,而是因为错误从一开始就存在。

答案 13 :(得分:1)

在非void函数中,所有执行路径都应以return语句结束。

在调试模式下,如果您忘记使用return语句结束这样的路径,则该函数通常默认返回0.

但是,在发布模式下,您的函数可能会返回垃圾值,这可能会影响程序的运行方式。

答案 14 :(得分:0)

另一个原因可能是数据库调用。 您是否在同一线程中多次保存和更新同一记录, 有时用于更新。 由于先前的create命令仍在处理中,因此更新可能失败或没有按预期方式工作,并且对于更新,db调用找不到任何记录。 这不会在调试中发生,因为调试器确保在着陆之前完成所有待处理的任务。

答案 15 :(得分:0)

我记得前一段时间我们在c / c ++中构建dll和pdb。

我记得这个:

  • 添加日志数据有时会使错误移动或消失,或者出现完全其他错误(因此它不是真正的选项)。
  • 由于strcpy和strcat中的char分配以及char []等数组而导致的许多错误......
  • 我们通过运行边界检查器并简单地修复了一些 内存分配/ dealloc问题。
  • 很多时候,我们系统地浏览了代码并修复了一个char分配(就像通过所有文件一样)。
  • 肯定是内存分配和管理以及调试模式和发布模式之间的约束和差异。

然后希望最好。

我有时会暂时向客户端提供dll的调试版本,以便在处理这些错误时不会阻止生产。

答案 16 :(得分:0)

我刚刚经历过,当我打电话给一个没有恢复寄存器的汇编功能时。以前的值。

在&#34;发布&#34;配置,VS正在使用/ O2编译,它优化了代码的速度。因此,一些局部变量只是映射到CPU寄存器(用于优化),这些变量与上述功能共享,导致严重的内存损坏。

无论如何,看看你是否在代码中的任何地方间接地弄乱了CPU寄存器。

答案 17 :(得分:0)

这是可能的。如果它发生并且没有涉及条件编译,那么你可以非常确定你的程序是错误的,并且只是因为偶然的内存初始化甚至是内存中的布局而在调试模式下工作!