调试版本和发布版本的含义、区别和用途是什么?

8

可能重复:
Debug/Release difference

我想知道这两个词的含义:Debug build和Release build,以及它们之间的区别。

在什么情况下应该使用哪一个(我的意思是每个条件适用于哪一个),如果我在Visual Studio中创建一个简单的C++项目而不更改任何项目设置,那么我现在使用的是哪个构建版本?

我之所以问这个问题,是因为我正在尝试使用wxWidgets 2.9.4制作GUI,并且它们给出了不同的添加所需.lib文件的方法。这些是:

release ANSI static

debug ANSI static

release Unicode static

debug Unicode static

请提供详细的答案。


1
你自己调查了什么?你尝试过谷歌搜索“Debug vs Release”吗? - default
1
@ Jakob S:但这是.NET,不是C++。 - huseyin tugrul buyukisik
1
虽然语言不同,但调试和发布版本之间的区别并没有改变。 - Some programmer dude
那我们还在等什么呢?赶快标记它! - huseyin tugrul buyukisik
2
@JoachimPileborg 是的。与.NET / Java相比,C ++在发布模式下删除的信息要多得多。有时您甚至无法检查变量的值,因为编译器已将其优化掉了。 - Tobias Langner
显示剩余4条评论
4个回答

29

Debug build和release build只是名称,它们并没有实际的意义。

根据您的应用程序,您可以使用不同的编译器和链接器选项以一种、两种或多种不同的方式构建它。大多数应用程序应该只构建一个版本:您测试和调试的程序与客户所使用的完全相同。在某些情况下,使用两个不同的版本可能更实用:通常,客户端代码需要进行优化以提高性能,但在调试时不希望进行优化。还有一些情况,例如完整调试(即迭代器验证等)可能会导致代码过慢,甚至无法进行算法调试,因此您将使用带有完整调试检查、没有优化但没有迭代器调试的构建和带有优化的构建。

每当您开始一个应用程序时,都必须决定需要哪些选项,并创建相应的构建。您可以随意命名它们。

关于外部库(如wxwidgets):所有编译器在使用不同选项时都存在一些不兼容性。因此,提供库(除源代码以外的其他形式)的人必须根据许多问题提供几个不同的版本:

  • 发布版vs.调试版:发布版将使用一组更或少标准的优化选项(并且没有迭代器调试)进行编译;调试版则不进行优化,而进行迭代器调试。是否存在迭代器调试是通常会破坏二进制兼容性的一件事情。库供应商应记录哪些选项与每个版本兼容。

  • ANSI vs. Unicode:这可能意味着字符数据的窄char与宽wchar_t之间的区别。使用与您的应用程序相对应的任何一个。(请注意,这两者之间的差异远不止于一些编译器开关。您经常需要截然不同的代码,并且在所有情况下正确处理Unicode还远非易事;真正支持Unicode的应用程序必须了解如合成字符或双向书写等问题。)

  • 静态 vs. 动态: 这决定了库的链接和加载方式。通常,你会想要使用静态方式,至少在你打算在除开发机之外的其他机器上部署应用程序时是这样。但这也取决于许可证问题: 如果每个部署该库的计算机都需要一个许可证,使用动态方式可能更有意义。


  • 感谢您提供详细的答案,现在我明白应该使用哪个了。谢谢。 - Natwar Singh
    2
    谢谢。现在我完全理解了这个问题。调试构建中没有“魔法”。只是不同的编译器和链接器选项/标志。因此,如果我使用GCC和-g标志编译程序,则不会有性能惩罚。它只意味着调试符号包含在生成的文件中。性能惩罚来自不同的标志,如-D(以及编译时您的程序或底层库考虑到的哪些标志)以及像-O这样的优化选项等。 - Marko Kukovec
    1
    "-g" 会在技术上导致性能略微下降,因为二进制文件更大,但你是对的——是“O”和一些“D”标志使得差异。 - Russell Greene

    9
    在进行DEBUG构建时,项目被设置为不优化(或仅轻微优化)生成的代码,并告诉编译器添加调试信息(包括函数、变量和其他调试所需的信息)。预处理器设置为定义_DEBUG宏。
    另一方面,RELEASE构建具有更高级别的优化,不保存调试信息。预处理器设置为定义NDEBUG宏。
    另一个区别是某些“系统”宏(例如类似于ASSERT的宏)根据是否定义_DEBUGNDEBUG而执行不同操作。ASSERT在发布构建中不起作用,但在调试构建中进行检查并中止。 Unicode和非Unicode之间的区别主要是UNICODE预处理器宏,它告诉头文件是否应启用某些Unicode功能。其中一件事是,在Unicode构建中,TCHAR将被定义为wchar_t,而在非Unicode构建中将被定义为char

    有没有任何文件保存了“调试”信息? - ajaysinghnegi
    假设使用Visual Studio,调试信息(启用时)存储在“程序数据库”中(一个带有“.pdb”后缀的文件)。 - Some programmer dude

    3
    在调试版本中,你会得到更多的错误检查,所以如果出现问题,你可能会得到更详细的信息(但它会运行得更慢)。
    在调试版本中,在调试器下运行时,你将得到更多的信息。
    可以通过查看项目属性的预处理器定义来确定构建是否为调试版本:_DEBUG 将被定义。
    你将向客户发送发布版本。 (调试版本使用调试库,在大多数非开发计算机上不存在)

    你得到你所要求的。你可以在“发布”模式下关闭优化,也可以在“调试”模式下打开它。这些模式只是名称,对于大多数应用程序并不真正相关。 - James Kanze
    在调试时关闭优化是个好主意 - 否则当你使用调试器来逐步执行代码时,会变得非常混乱。 - ravenspoint

    3
    如果你想要将静态库链接到项目中,那么它必须使用与编译代码相同的设置进行编译。这就是为什么会有Debug和Release版本的库的原因。此外,你需要指定是否使用unicode或ansi。对于这个问题,答案非常简单 - 只需使用unicode。
    在Release版本中与Debug版本相比有什么不同以使得它们无法混合?主要的区别在于内存管理。Debug版本的内存管理会做很多额外的事情来让你尽早发现错误。例如,可以检查代码覆盖的canaries等。未初始化的内存会被初始化为特定的模式,...此外,在release中有许多优化是在debug中没有使用的。这样可以使release运行更快,但也使得调试代码变得困难。方法可能被优化掉并且被内联,参数传递可能被优化以使用寄存器,...。
    因此,在C++中,你至少需要管理两个配置。一个使用debug库链接的Debug配置,用于开发和测试。另一个使用release库链接的Release配置,用于发布。但是不要忘记你还需要测试Release,因为它可能会有不同于Debug配置的行为。

    只有在需要的情况下才使用Unicode。Unicode比纯ANSI复杂得多,虽然如果您计划在单字节编码(例如大部分亚洲地区)无法覆盖的地方使用程序,则必须使用它,但确实需要更多的努力。 - James Kanze
    没有太多额外的努力 - 特别是因为现代 Windows 上的所有 API 函数都需要 Unicode 字符串。我同意,如果你真的想翻译东西,那么需要更多的努力 - 但这并不取决于你使用 std::wstring 和 wchar_t* 而不是 std::string 和 char*。 - Tobias Langner
    我同意使用wchar_t并不比使用char更困难。但是,“使用Unicode”涉及的远不止使用wchar_t,除非你正在使用Unicode(或者你正在使用需要超过256个字符的语言),否则使用wchar_t没有任何意义。这只是增加了复杂性而已。(说到这一点,除非我要转换文本,否则即使对于Unicode,我也会使用char和UTF-8。这样可以让事情变得简单得多。) - James Kanze
    关于Windows下的系统接口...无论Windows声称自己能做什么,它都不能改变世界。现代世界是以8位为导向的,从互联网开始。Windows小心翼翼地提供了8位和16位接口;使用16位接口会让你陷入困境,并意味着你永远无法与其他任何东西通信,或将你的代码移植到其他任何地方。这对于某些GUI应用程序可能是有道理的,但通常不是。 - James Kanze
    作为一个例子,有一些金丝雀可以检查代码的覆盖。未初始化的内存会被初始化为特定的模式。这正是我在寻找的。您能澄清一下这里的金丝雀是什么吗?还有其他的例子吗? - Mudit Jain

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