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

C++ 调试模式下发布版本中不存在错误的常见原因,c++,release-mode,debug-mode,C++,Release Mode,Debug Mode,错误和异常程序行为的典型原因是什么?这些错误和异常程序行为只在发布编译模式下出现,但在调试模式下不会出现?您需要提供更多信息,但是的,这是可能的。这取决于调试版本的功能。您可能会有日志记录或额外的检查,但这些检查不会被编译到发布版本中。这些只进行调试的代码路径可能会产生意外的副作用,这些副作用会以奇怪的方式更改状态或影响变量。调试生成通常运行较慢,因此这可能会影响线程和隐藏竞争条件。对于发布编译的直接优化也是一样,发布编译有可能(尽管现在不太可能)将某些东西作为优化而短路。当然,例如,如果您使用

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

您需要提供更多信息,但是的,这是可能的。这取决于调试版本的功能。您可能会有日志记录或额外的检查,但这些检查不会被编译到发布版本中。这些只进行调试的代码路径可能会产生意外的副作用,这些副作用会以奇怪的方式更改状态或影响变量。调试生成通常运行较慢,因此这可能会影响线程和隐藏竞争条件。对于发布编译的直接优化也是一样,发布编译有可能(尽管现在不太可能)将某些东西作为优化而短路。

当然,例如,如果您使用如下结构

#if DEBUG

//some code

#endif

多次,在C++中的调试模式中,所有变量都是空初始化的,而除非明确说明,否则在释放模式中不会发生相同的变量。 检查是否有任何调试宏和未初始化的变量

如果您的程序使用线程,那么在发布模式下优化也会导致一些问题


还要检查所有异常,例如,与发布模式没有直接关系,但有时我们只是忽略一些关键异常,如VC++中的mem访问冲突,但至少在其他操作系统(如Linux、Solaris)中,这可能是一个问题。理想情况下,您的程序不应该捕获诸如访问空指针之类的关键异常

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

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

在.NET中,即使您不使用类似于
\if debug
的条件编译,编译器在发行版模式下的优化仍比在调试模式下的优化自由得多,这也可能导致只发布bug。

其他差异可能是:


  • 在垃圾收集语言中 收集器通常更具攻击性 在释放模式下
  • 内存的布局可能会改变 经常是不同的
  • 记忆可能是 初始化方式不同(如可以 在调试模式下归零,或重复使用更多 积极地释放)
  • 当地人可能 被提升为在发布中注册值,可以 导致浮点问题 价值观

一个常见的陷阱是在断言中使用带有副作用的表达式。

它可以,尤其是在C领域

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

另一个原因可能是优化(发布版本通常打开,调试时关闭)。代码和数据布局可能已经优化,例如,当调试程序刚刚访问未使用的内存时,发布版本现在正在尝试访问保留内存,甚至指向代码


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

这是可能的。如果发生这种情况,并且不涉及条件编译,那么您可以非常确定您的程序是错误的,并且仅由于偶然的内存初始化,甚至内存中的布局而在调试模式下工作

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


尝试在启用较少优化的情况下编译代码。

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

除此之外,这是不可能的。调试代码和发布代码的编译方式不同,在是否在调试器下运行的情况下,代码的执行方式也不同,但如果这些差异中的任何一个导致性能差异以外的任何差异,那么问题始终存在

在调试版本中,错误可能没有发生(因为时间或内存分配不同),但这并不意味着错误不存在。可能还有其他与调试模式无关的因素,这些因素会改变代码的计时,从而导致错误是否发生,但归根结底,如果代码是正确的,那么在任何情况下都不会发生错误


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

CRT库函数在调试与发布(/MD vs/MDd)中的行为不同


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

过去,我曾被许多bug所困扰,这些bug在调试版本中表现良好,但在发布版本中崩溃。有许多潜在的原因(当然包括那些已经在这篇文章中总结过的原因),我已经被以下所有的原因抓住了:

  • #ifdef_DEBUG
    中的成员变量或成员函数,因此类在DEBUG b中的大小不同