自己一直不怎么用assert,主要是因为以前感觉貌似assert不是标准里提供的,而是特定编译器提供的
刚才查了查C语言他爸那本书,
原来在附录里提到了assert
B.6部分
(直接拷贝文字,中文字符乱码,所以拷贝了图片)
查了查VS2008中具体实现
如下:
#define assert(_Expression) (void)( (!!(_Expression)) || (_wassert(_CRT_WIDE(#_Expression), _CRT_WIDE(__FILE__), __LINE__), 0) )
注意,这个地方_wasser这个w是因为VS2008中工程默认字符集为Unicode,即宽字符集
!!(_Expression)
两个感叹号的做法在某些地方常见到,比较巧妙
作用为把各种值转为0或者1
比如!!5 == 1
!!0 == 0
具体实现为
#ifdef _UNICODE
void __cdecl _wassert (
const wchar_t *expr,
const wchar_t *filename,
unsigned lineno
)
#else /* _UNICODE */
void __cdecl _assert (
const char *expr,
const char *filename,
unsigned lineno
)
#endif /* _UNICODE */
{
/*
* Build the assertion message, then write it out. The exact form
* depends on whether it is to be written out via stderr or the
* MessageBox API.
*/
if ( (_set_error_mode(_REPORT_ERRMODE)== _OUT_TO_STDERR) ||
((_set_error_mode(_REPORT_ERRMODE) == _OUT_TO_DEFAULT) &&
(__app_type == _CONSOLE_APP)) )
{
#ifdef _UNICODE
{
TCHAR assertbuf[ASSERTBUFSZ];
HANDLE hErr ;
DWORD written;
hErr = GetStdHandle(STD_ERROR_HANDLE);
if(hErr!=INVALID_HANDLE_VALUE && hErr!=NULL)
{
if(swprintf(assertbuf, ASSERTBUFSZ,_assertstring,expr,filename,lineno) >= 0)
{
if(GetFileType(hErr) == FILE_TYPE_CHAR)
{
if(WriteConsoleW(hErr, assertbuf, (unsigned long)wcslen(assertbuf), &written, NULL))
{
abort();
}
}
}
}
}
#endif /* _UNICODE */
/*
* Build message and write it out to stderr. It will be of the
* form:
* Assertion failed: <expr>, file <filename>, line <lineno>
*/
if ( !anybuf(stderr) )
/*
* stderr is unused, hence unbuffered, as yet. set it to
* single character buffering (to avoid a malloc() of a
* stream buffer).
*/
(void) setvbuf(stderr, NULL, _IONBF, 0);
_ftprintf(stderr, _assertstring, expr, filename, lineno);
fflush(stderr);
}
else {
int nCode;
TCHAR * pch;
TCHAR assertbuf[ASSERTBUFSZ];
TCHAR progname[MAX_PATH + 1];
/*
* Line 1: box intro line
*/
_ERRCHECK(_tcscpy_s( assertbuf, ASSERTBUFSZ, BOXINTRO ));
_ERRCHECK(_tcscat_s( assertbuf, ASSERTBUFSZ, dblnewline ));
/*
* Line 2: program line
*/
_ERRCHECK(_tcscat_s( assertbuf, ASSERTBUFSZ, PROGINTRO ));
progname[MAX_PATH] = _T('\0');
if ( !GetModuleFileName( NULL, progname, MAX_PATH ))
_ERRCHECK(_tcscpy_s( progname, MAX_PATH + 1, _T("<program name unknown>")));
pch = (TCHAR *)progname;
/* sizeof(PROGINTRO) includes the NULL terminator */
if ( (sizeof(PROGINTRO)/sizeof(TCHAR)) + _tcslen(progname) + NEWLINESZ > MAXLINELEN )
{
pch += ((sizeof(PROGINTRO)/sizeof(TCHAR)) + _tcslen(progname) + NEWLINESZ) - MAXLINELEN;
_ERRCHECK(_tcsncpy_s( pch, (MAX_PATH + 1) - (pch - progname), dotdotdot, DOTDOTDOTSZ ));
}
_ERRCHECK(_tcscat_s( assertbuf, ASSERTBUFSZ, pch ));
_ERRCHECK(_tcscat_s( assertbuf, ASSERTBUFSZ, newline ));
/*
* Line 3: file line
*/
_ERRCHECK(_tcscat_s( assertbuf, ASSERTBUFSZ, FILEINTRO ));
/* sizeof(FILEINTRO) includes the NULL terminator */
if ( (sizeof(FILEINTRO)/sizeof(TCHAR)) + _tcslen(filename) + NEWLINESZ > MAXLINELEN )
{
size_t p, len, ffn;
pch = (TCHAR *) filename;
ffn = MAXLINELEN - (sizeof(FILEINTRO)/sizeof(TCHAR)) - NEWLINESZ;
for ( len = _tcslen(filename), p = 1;
pch[len - p] != _T('\\') && pch[len - p] != _T('/') && p < len;
p++ );
/* keeping pathname almost 2/3rd of full filename and rest
* is filename
*/
if ( (ffn - ffn/3) < (len - p) && ffn/3 > p )
{
/* too long. using first part of path and the
filename string */
_ERRCHECK(_tcsncat_s( assertbuf, ASSERTBUFSZ, pch, ffn - DOTDOTDOTSZ - p ));
_ERRCHECK(_tcscat_s( assertbuf, ASSERTBUFSZ, dotdotdot ));
_ERRCHECK(_tcscat_s( assertbuf, ASSERTBUFSZ, pch + len - p ));
}
else if ( ffn - ffn/3 > len - p )
{
/* pathname is smaller. keeping full pathname and putting
* dotdotdot in the middle of filename
*/
p = p/2;
_ERRCHECK(_tcsncat_s( assertbuf, ASSERTBUFSZ, pch, ffn - DOTDOTDOTSZ - p ));
_ERRCHECK(_tcscat_s( assertbuf, ASSERTBUFSZ, dotdotdot ));
_ERRCHECK(_tcscat_s( assertbuf, ASSERTBUFSZ, pch + len - p ));
}
else
{
/* both are long. using first part of path. using first and
* last part of filename.
*/
_ERRCHECK(_tcsncat_s( assertbuf, ASSERTBUFSZ, pch, ffn - ffn/3 - DOTDOTDOTSZ ));
_ERRCHECK(_tcscat_s( assertbuf, ASSERTBUFSZ, dotdotdot ));
_ERRCHECK(_tcsncat_s( assertbuf, ASSERTBUFSZ, pch + len - p, ffn/6 - 1 ));
_ERRCHECK(_tcscat_s( assertbuf, ASSERTBUFSZ, dotdotdot ));
_ERRCHECK(_tcscat_s( assertbuf, ASSERTBUFSZ, pch + len - (ffn/3 - ffn/6 - 2) ));
}
}
else
/* plenty of room on the line, just append the filename */
_ERRCHECK(_tcscat_s( assertbuf, ASSERTBUFSZ, filename ));
_ERRCHECK(_tcscat_s( assertbuf, ASSERTBUFSZ, newline ));
/*
* Line 4: line line
*/
_ERRCHECK(_tcscat_s( assertbuf, ASSERTBUFSZ, LINEINTRO ));
_ERRCHECK(_itot_s( lineno, assertbuf + _tcslen(assertbuf), ASSERTBUFSZ - _tcslen(assertbuf), 10 ));
_ERRCHECK(_tcscat_s( assertbuf, ASSERTBUFSZ, dblnewline ));
/*
* Line 5: message line
*/
_ERRCHECK(_tcscat_s( assertbuf, ASSERTBUFSZ, EXPRINTRO ));
/* sizeof(HELPINTRO) includes the NULL terminator */
if ( _tcslen(assertbuf) +
_tcslen(expr) +
2*DBLNEWLINESZ +
(sizeof(INFOINTRO)/sizeof(TCHAR)) - 1 +
(sizeof(HELPINTRO)/sizeof(TCHAR)) > ASSERTBUFSZ )
{
_ERRCHECK(_tcsncat_s( assertbuf, ASSERTBUFSZ, expr,
ASSERTBUFSZ -
(_tcslen(assertbuf) +
DOTDOTDOTSZ +
2*DBLNEWLINESZ +
(sizeof(INFOINTRO)/sizeof(TCHAR))-1 +
(sizeof(HELPINTRO)/sizeof(TCHAR)))));
_ERRCHECK(_tcscat_s( assertbuf, ASSERTBUFSZ, dotdotdot ));
}
else
_ERRCHECK(_tcscat_s( assertbuf, ASSERTBUFSZ, expr ));
_ERRCHECK(_tcscat_s( assertbuf, ASSERTBUFSZ, dblnewline ));
/*
* Line 6, 7: info line
*/
_ERRCHECK(_tcscat_s(assertbuf, ASSERTBUFSZ, INFOINTRO));
_ERRCHECK(_tcscat_s(assertbuf, ASSERTBUFSZ, dblnewline ));
/*
* Line 8: help line
*/
_ERRCHECK(_tcscat_s(assertbuf, ASSERTBUFSZ, HELPINTRO));
/*
* Write out via MessageBox
*/
nCode = __crtMessageBox(assertbuf,
_T("Microsoft Visual C++ Runtime Library"),
MB_ABORTRETRYIGNORE|MB_ICONHAND|MB_SETFOREGROUND|MB_TASKMODAL);
/* Abort: abort the program */
if (nCode == IDABORT)
{
/* raise abort signal */
raise(SIGABRT);
/* We usually won't get here, but it's possible that
SIGABRT was ignored. So exit the program anyway. */
_exit(3);
}
/* Retry: call the debugger */
if (nCode == IDRETRY)
{
_DbgBreak();
/* return to user code */
return;
}
/* Ignore: continue execution */
if (nCode == IDIGNORE)
return;
}
abort();
}