Q_ASSERT 发布构建语义

Posted

技术标签:

【中文标题】Q_ASSERT 发布构建语义【英文标题】:Q_ASSERT release build semantics 【发布时间】:2012-09-24 21:32:24 【问题描述】:

我在发布版本中找不到关于 Q_ASSERT 语义的明确声明。如果没有断言检查,那么断言表达式是否被评估?

考虑下面的代码

Q_ASSERT(do_something_report_false_if_failed());

do_something_report_false_if_failed() 会在所有可能的 Qt 构建配置下运行吗?这样做会更安全吗(尽管更冗长且可读性更低):

bool is_ok = do_something_report_false_if_failed();
Q_ASSERT(is_ok)

后一种方法的缺点是 ASSERT 失败不那么冗长,但也许它更清楚地表明该语句已执行?

【问题讨论】:

【参考方案1】:

Q_ASSERT 中的表达式将在非调试构建配置中进行评估。

考虑下面来自Qt repo的源代码。

#if !defined(Q_ASSERT)
#  ifndef QT_NO_DEBUG
#    define Q_ASSERT(cond) ((!(cond)) ? qt_assert(#cond,__FILE__,__LINE__) : qt_noop())
#  else
#    define Q_ASSERT(cond) qt_noop()    
#  endif    
#endif

如果定义了QT_NO_DEBUG,则整个Q_ASSERT 语句将替换为qt_noop(),从而删除它之前包含的任何表达式。

永远不要依赖Q_ASSERT 语句中的表达式产生的任何副作用。从技术上讲,仍然可以确保QT_NO_DEBUG 没有在特定的构建配置中定义,但这不是一个好主意™。

【讨论】:

这与普通的assertNDEBUG 宏完全相同。【参考方案2】:

这在Qt5.5 中似乎有所不同(但不是更早 - 请参阅Qt5.4):

#if !defined(Q_ASSERT)
#  if defined(QT_NO_DEBUG) && !defined(QT_FORCE_ASSERTS)
#    define Q_ASSERT(cond) do   while ((false) && (cond))
#  else
#    define Q_ASSERT(cond) ((!(cond)) ? qt_assert(#cond,__FILE__,__LINE__) : qt_noop())
#  endif
#endif

我现在在 Visual Studio 2013 中收到很多“警告 C4127:条件表达式是常量”。

更新: Qt5.5 release notes说:

Q_ASSERT 现在即使在释放模式下也会扩展条件 断言被禁用,尽管在无法访问的代码路径中。这 解决了关于变量和函数的编译器警告 在发布模式下未使用,因为它们仅用于断言。 不幸的是,隐藏了这些函数和变量的代码库 via #ifndef 将需要删除条件以使用 Qt 5.5 进行编译。

【讨论】:

将 Q_ASSERT 和 Q_ASSERT_X 重新定义回 noop 有帮助 这是gerrit的变化:codereview.qt-project.org/#/c/94460/3 我也有同样的问题。这在 Qt 版本 > 5.5 中是否已修复?

以上是关于Q_ASSERT 发布构建语义的主要内容,如果未能解决你的问题,请参考以下文章

QT: 自定义断言;

QtApplets-Q_ASSERT使用

Qt QVector “isDetached()“

Xcode 5 等效于构建设置中的 NS_BLOCK_ASSERTIONS

assertion的用法

if和assert的区别