环境:
$ g++ --version
g++ (Ubuntu 7.4.0-1ubuntu1~18.04) 7.4.0
众所周知,可以通过在包含assert
(NDEBUG
)之前定义的assert.h
来禁用用于调试的类函数宏cassert
。但是,在我的环境中阅读/usr/include/assert.h
后,我发现了下面的代码。
#if defined __cplusplus && __GNUC_PREREQ (2,95)
# define __ASSERT_VOID_CAST static_cast<void>
#else
# define __ASSERT_VOID_CAST (void)
#endif
#ifdef NDEBUG
# define assert(expr) (__ASSERT_VOID_CAST (0))
# ifdef __USE_GNU
# define assert_perror(errnum) (__ASSERT_VOID_CAST (0))
# endif
#else /* Not NDEBUG. */
因此,即使使用NDEBUG
,assert
也会扩展到某个值,因此对性能的影响不大,但可以肯定地(如果在预处理步骤之后未进行优化)。由于C ++标准允许类似函数的宏带有空值,因此
#ifdef NDEBUG
#define assert(expr)
#endif
将是一个很好的实现。
有什么理由应该选择非空值?
答案 0 :(得分:6)
在定义NDEBUG
时宏具有值的一个原因是因为C标准要求它具有一个-甚至规定了它应该是什么。
¶1标头
<assert.h>
定义了assert
和static_assert
宏,并引用了另一个宏,未由NDEBUG
<assert.h>
定义的。如果在源文件中包含
NDEBUG
的位置将<assert.h>
定义为宏名,则将assert
宏定义为#define assert(ignore) ((void)0)
每次包含
assert
时,都会根据NDEBUG
的当前状态重新定义<assert.h>
宏。¶2
assert
宏应实现为宏,而不是实际功能。如果取消了宏定义以访问实际功能,则该行为未定义。...
简介
#include <assert.h> void assert(scalar expression);
说明
¶2
assert
宏将诊断测试放入程序中。它扩展为void
表达式。执行时,如果expression
(应为标量类型)为false(即比较等于0),则assert
宏将写入有关失败的特定调用的信息(包括文本)参数,源文件的名称,源行号和封闭函数的名称-后者分别是预处理宏__FILE__
和__LINE__
的值以及标识符__func__
)上的标准错误流以实现定义的格式。 191)然后调用abort
函数。返回
¶3
assert
宏不返回任何值。191)所写消息的形式可能是:
Assertion failed: expression, function abc, file xyz, line nnn.
C ++ 11标准说(§19.3断言)说:
头文件
<cassert>
…提供了一个宏,用于记录C ++程序声明,并提供了一种禁用声明检查的机制。...
内容与标准C库头文件
<assert.h>
相同。
因此,相同的规则适用于C ++和C。C++标准未明确指出C ++ static_assert
和C _Static_assert
之间的区别(以及{{1}的定义}作为static_assert
标头的C版本中的_Static_assert
。最终结果还是差不多。
答案 1 :(得分:1)
要使用NDEBUG,必须在#define NDEBUG
之前写#include <cassert>
。如果要跳过assert(expression)
语句,请编写#define NDEBUG
或用其他注释方式。