为啥在发布版本中断言宏的定义不能只是`#define assert(expression) 0`?

Posted

技术标签:

【中文标题】为啥在发布版本中断言宏的定义不能只是`#define assert(expression) 0`?【英文标题】:Why the definition of the assert macro, in a release build, cannot be just `#define assert(expression) 0`?为什么在发布版本中断言宏的定义不能只是`#define assert(expression) 0`? 【发布时间】:2020-05-09 18:18:14 【问题描述】:

这是 Visual Studio 2019 中断言宏的定义

#ifdef NDEBUG

    #define assert(expression) ((void)0)

#else

    _ACRTIMP void __cdecl _wassert(
        _In_z_ wchar_t const* _Message,
        _In_z_ wchar_t const* _File,
        _In_   unsigned       _Line
        );

    #define assert(expression) (void)(                                                       \
            (!!(expression)) ||                                                              \
            (_wassert(_CRT_WIDE(#expression), _CRT_WIDE(__FILE__), (unsigned)(__LINE__)), 0) \
        )

#endif

正如你在上面看到的,在发布版本中宏断言的定义是

#define assert(expression) ((void)0)

为什么不能只是#define assert(expression) 0

【问题讨论】:

相关:Why is assert is defined as (void)0?。 (不是重复的,因为它专注于另一种选择,但将来发现这个问题的人可能会感兴趣。) @JaMiT 我不相信链接问题中给出的答案。所以我决定在Visual C++ 中问同样的问题。我在那里得到了 Igor Tandetnik 的精彩回答。 * 耸耸肩 * Igor 确实给出了一个很好的例子。但是,您可能会注意到此页面上的某个位置(在宽浏览器中位于右侧,在窄浏览器中位于底部)现在有一个“链接”部分,其中包含指向 “为什么断言定义为 (void)0? ".我可以通过添加评论向该部分添加相关的 SO 问题。添加相关的非 SO 问题并不是那么简单。 ;) 【参考方案1】:

这可以防止使用assert 作为表达式。因此,如果有人这样做(错误地):

a = assert(something);

编译器会在发布和调试版本中抛出错误。

【讨论】:

我花了一段时间才接受你说的话。但你的答案是正确的。顺便说一句,答案很好! @Belloc 不一定只有一个“正确”的答案;可能有多种原因。此外,这个答案有点不准确。 (void) 演员表防止 assert() 成为 rvalue,但它仍然可以用作 expression。例如:condition ? assert(something) : assert(somethingElse)assert(condition), puts("hello") @jamesdlin 你会发现我接受 Julien 的回答而不是你的here 的原因。基本上,朱利安的回答似乎更好地解释了这个例子,因为在这种情况下没有警告。我还注意到朱利安的回答有一点不准确。但在我看来,这是一个很小的问题,不能做出有利于他的决定。【参考方案2】:

一些编译器可能希望 (void) 强制转换来抑制有关未使用值的表达式的警告。

【讨论】:

以上是关于为啥在发布版本中断言宏的定义不能只是`#define assert(expression) 0`?的主要内容,如果未能解决你的问题,请参考以下文章

php中const和define的区别

C语言中assert断言的用法?

C预处理

C++ 中函数别名的“#define”宏的替代方案

libc6:断言宏定义中的逗号运算符

C语言问题,宏定义中的参数为啥要定义,不是主函数中的参数直接替换吗?