抠下VS2008里assert的实现

来源:互联网 发布:代聊都用什么软件 编辑:程序博客网 时间:2024/05/16 23:33

自己一直不怎么用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 _UNICODEvoid __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();}