c语言——面试之assert断言使用

查看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>中,其作用是如果它的条件返回错误,则终止程序执行,
  1. 原型定义:
  ● #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():这个函数是一个内部函数,它就是异常中止你运行的程序.

猜你喜欢

转载自blog.csdn.net/qq_38936579/article/details/78171037