查看vs 2013assert定义,如下:
#ifdef NDEBUG
#define assert(_Expression) ((void)0)
#else /* NDEBUG */
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
_CRTIMP void __cdecl _wassert(_In_z_ const wchar_t * _Message, _In_z_ const wchar_t *_File, _In_ unsigned _Line);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#define assert(_Expression) (void)( (!!(_Expression)) || (_wassert(_CRT_WIDE(#_Expression), _CRT_WIDE(__FILE__), __LINE__), 0) )
#endif /* NDEBUG */
assert宏的原型定义在<assert.h>中,其作用是如果它的条件返回错误,则终止程序执行,
- 原型定义:
● #include <assert.h>
● void assert( int expression );
头文件定义了assert宏,引用了NDEBUG,后者未定义在该头文件内
2 代码解释:
#ifdef NDEBUG
#define assert(_Expression) ((void)0)
当调 试完成后,如果定义了NDEBUG,关闭断言,优化生成的代码
assert的宏定义
代码如下:
#define assert(_Expression) (void)( (!!(_Expression)) ||
(_wassert(_CRT_WIDE(#_Expression), _CRT_WIDE(__FILE__), __LINE__), 0) )
_Expresssion若为false,则!false=true,!true=false,此时继续执行||以后的语句,故会打印出出错信息,终止程序,若_Expression为true,则!true=false,!false=true,此时不再执行||以后的语句,故不会打印出信息 使用了||运算的截断 和 !!(_Expression)两次取否 ,#是把跟在后面的参数转换成一个字符串
_wassert的宏定义
代码如下:
_wassert(_In_z_ const wchar_t * _Message, _In_z_ const wchar_t *_File, _In_ unsigned _Line);
打印出出错信息调用了abort()函数来终止程序的运行。
问题:
频繁的调用会极大的影响程序的性能,增加额外的开销。
在调试结束后,可以通过在包含#include <assert.h>的语句之前插入 #define NDEBUG 来禁用assert调用
#define NDEBUG
#include <assert.h>
摘自《高质量C/C++编程指南》Page 41-42...
程序一般分为Debug 版本和Release 版本,Debug 版本用于内部调试,Release 版本发行给用户使用。
断言assert 是仅在Debug 版本起作用的宏,它用于检查“不应该”发生的情况。assert 不是一个仓促拼凑起来的宏。为了不在程序的Debug 版本和Release 版本引起差别,assert 不应该产生任何副作用。所以assert 不是函数,而是宏。程序员可以把assert看成一个在任何系统状态下都可以安全使用的无害测试手段。如果程序在 assert 处终止了,并不是说含有该assert 的函数有错误,而是调用者出了差错,assert 可以帮助我们找到发生错误的原因。
assert宏注意事项
- 最好使用assert宏检查一个条件,就是不要用&&或者||操作符,这样更容易发现是哪个条件出现问题,在需要的时候,多写几个assert宏。
- 不要使用assert进行变量修改,如assert(k++>10),因为我们可能会禁用这个宏,此时,k++是不会执行的,正如上面我们看到的一样。
- assert不是条件过滤。
自定义实现ASSERT宏
#include<stdio.h>
#define assert(_Expression) (void)( (!!(_Expression)) || _assert(#_Expression, __FILE__, __LINE__), 0 )
void _assert(_Expression, __FILE__, __LINE__)
{
printf("Assertion Failed: %s, file%s line %d",_Expression, __FILE__, __LINE__);
abort();
}
(void)( (!!(_Expression)) || _assert(#_Expression, __FILE__, __LINE__), 0 )
这里利用了||的短路性质,就是条件为真,它就不执行后面的了,为假才执行。如果表达式e为真,则为(void)0;表达式e为假,则调用_assert()这函数
- #exp会在预处理产生一个字符串.
- __FILE__,__LINE__,分别表示文件位置和行数。
- abort():这个函数是一个内部函数,它就是异常中止你运行的程序.