【问题标题】:How to put assert into release builds in C/C++如何将断言放入 C/C++ 中的发布版本中
【发布时间】:2010-10-11 21:02:37
【问题描述】:

我只需要运行 ship build 并且我需要在 release build 中的某些条件下断言以查看问题是否已解决。我该怎么做?

【问题讨论】:

  • 什么平台? Windows 和 Visual Studio?
  • 通常不建议在发布版本中保留断言。但是,您可能有充分的理由这样做;尽管如此,它也可能不被称为“断言”,在这种情况下它不应该使用相同的函数调用。
  • 为什么不使用简单的条件呢?想想如果“断言”失败,你的程序应该做什么。您不应该只在发布版本中调用std::abort。如果您正在开发应用程序,请抛出异常。如果您正在开发库,请提供调试版本。

标签: c++ c release assert


【解决方案1】:

只需直接调用assert 宏定义中在发布模式下处于活动状态的部分即可。

您可以在this great article by Miro Samek (PDF) 中找到非常有用的 C++ 断言定义。然后,您可以稍微调整它们以满足您的需求。例如,您可以创建另一个宏 release_assert,它的作用与 assert 相同,但不管它是处于发布模式还是调试模式。

【讨论】:

  • 但这是实现定义的。你不能便携。
【解决方案2】:

使用 Visual Studio 时,您可以将 NDEBUG 预编译器定义取消定义为发布版本中的活动断言。

例如,您可以在 Projekt 设置中为 /U 选项设置 $(undefesTheNDEBUG),然后将环境变量 undefesTheNDEBUG 定义为 NDEBUG (SET undefesTheNDEBUG=NDEBUG) 或将其与 msbuild 一起传递 (/p:undefesTheNDEBUG=NDEBUG)

【讨论】:

    【解决方案3】:

    实际上 - 如果您可以接受,我会提供调试版本。如果不需要发布版本的性能,请使用调试。它往往有更少的错误(这是一个严重的过度简化,如果你的程序没有错误,只是切换到发布不会改变这一点,但由于编译器在调试模式下所做的事情,错误可能不会发生和/或有后果较轻)。

    也许也可以只优化程序的时间关键部分。

    还可以简化调试。

    【讨论】:

    • 嗯,在 Visual C++ 中,您不能合法地交付 C++ 调试运行时,因此如果您使用 DLL 运行时(即 /MD 或 /MDd开关)。
    • 尽管这个答案被否决了,但我相信它触及了一个重要的点,即在开发人员主要测试的 [调试版本] 和发布的内容之间更改一堆变量的概念,不一定是个好主意。经验丰富的开发人员会证明,发布版本和调试版本通常表现出不同的行为。
    【解决方案4】:

    为什么不直接定义自己的断言:

    #define assert(x) MessageBox(...);
    

    【讨论】:

    • 投了赞成票,因为这是这里唯一的建议。虽然建议放一个行号,并说明出了什么问题。虽然接下来的事情也是设计你自己的崩溃系统,所以当一个断言命中时,你会做一个自动发送给你的内存转储。
    • 我喜欢这个,但想提出一个迟到六年的建议——为您的断言使用不同的名称,即您希望存在于发布和调试版本中,例如 ndbgassert 或类似的。这样您就可以在两者之间进行选择。
    • 如何断言MessageBox??不应该先检查条件吗?
    【解决方案5】:

    我喜欢将它定义为抛出某种从 std::runtime_error 派生的 assert_exception。然后在某个地方抓住它并做一些有用的事情。

    【讨论】:

      【解决方案6】:

      ASSERT 的默认行为是在 Debug 配置下中止程序,但这通常在 Release 配置下变成无操作。我相信它通过检查预处理器 NDEBUG 宏的存在来做到这一点。我现在不在工作,所以无法查看。

      我认为解决此问题的最简单方法是修改 Debug 配置以将所有优化提升到与 Release(内存中的 O2)相同的级别,然后重新构建您的软件。这将为您提供与发布版本相同的性能和速度,但它仍将定义 NDEBUG 预处理器宏,这意味着所有失败的 ASSERT 仍将导致程序中止。以后记得把优化级别改回来,不然在Debug配置下调试就麻烦了。

      不过,一般来说,ASSERT 应该只用于编程前提条件,而绝不能用于处理交付软件中的故障。您希望在开发过程中快速失败,但优雅地在用户面前失败。

      【讨论】:

        【解决方案7】:

        取消定义 NDEBUG 宏 - 您可以在本地围绕要保留在构建中的断言执行此操作:

        #undef NDEBUG
        #include <assert.h>   // reinclude the header to update the definition of assert()
        

        或者做任何你需要做的事情,这样你的构建过程就不会首先定义 NDEBUG 宏。

        【讨论】:

        • 如果assert.h 包含在pch 文件中,它可能不起作用。
        • 我刚刚尝试过——它并不总是有效。如果我把它作为我的 .cpp 中的前两行,它不会做任何事情,但是当我把它放在我的 main() 上方时它会起作用。
        • 那么似乎必须重新定义 NDEBUG 并再次包含 assert.h(可能包含其他一些标头)。
        猜你喜欢
        • 1970-01-01
        • 2011-01-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-08-25
        • 1970-01-01
        • 2020-03-28
        • 1970-01-01
        相关资源
        最近更新 更多