assert的作用是现计算表达式 expression ,如果其值为假(即为0),那么它先向stderr打印一条出错信息,然后通过调用 abort 来终止程序运行。
assert的宏定义在#include <assert.h>
具体代码如下
***
*assert.h - define the assert macro
*
* Copyright (c) Microsoft Corporation. All rights reserved.
*
*Purpose:
* Defines the assert(exp) macro.
* [ANSI/System V]
*
* [Public]
*
****/
#ifdef _CRTBLD
#ifndef _ASSERT_OK
#error assert.h not for CRT internal use, use dbgint.h
#endif /* _ASSERT_OK */
#include <cruntime.h>
#endif /* _CRTBLD */
#include <crtdefs.h>
#undef assert
#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的使用场景 在debug模式下使用,如果非debug模式表达式会被替换为(void)0
宏如果这样做在运行的时候直接将这一行越过不进行汇编所以NDEBUG的assert不会被执行;
所以void((0))是指编译器不对这一行进行编译直接去下一行
#define assert(_Expression) (void)( (!!(_Expression)) || (_wassert(_CRT_WIDE(#_Expression), _CRT_WIDE(__FILE__), __LINE__), 0) )
函数代码如下继续分析
xtern int mingw_app_type;
void __cdecl _wassert(const wchar_t *_Message,const wchar_t *_File,unsigned _Line)
{
wchar_t *msgbuf = (wchar_t *) malloc (8192*sizeof(wchar_t));
if (!_File || _File[0] == 0)
_File = L"<unknown>";
if (!_Message || _Message[0] == 0)
_Message = L"?";
_snwprintf (msgbuf, 8191,
L"Assertion failed!\n\nFile: %ws, Line %u\n\nExpression: %ws",
_File,_Line, _Message);
if (mingw_app_type == 0)
fwprintf (stderr, L"%ws\n", msgbuf);
else
OutputDebugStringW(msgbuf);
abort ();
}
这个代码的逻辑如下后两个参数不需要去分析下具体就是将asset中的内容打印在屏幕是上并调用abort终止程序
所以在使用assert中应注意一下几点
每个assert只检验一个条件,因为同时检验多个条件时,如果断言失败,无法直观的判断是哪个条件失败
不用再asset中改变需要断言的变量的值否则在非debug模式下不能使用。
assert不要作为条件判断,因为不满足之后直接回终止掉进程
asset断言只会停止到当前,并且对后面的错误没办法直接观察到。