Let's obey standards
Wednesday, 3. May 2006, 14:55:19
assert macro, defined in ISO 9899 standard, under Program Diagnostics section (7.2) provides an assertion mechanism, as you may already know. What it means is that:
void f(void *p)
{
assert(p); /* ensure p is not NULL */
/* ... */
}
If accidentally f() is called with NULL parameter, program will stop and complain about situation, as we all expected. Usually, something like below appears:
Assertion failed on somesourcefile.c:441
Some libraries may also display a message like:
Assertion failed on somesourcefile.c:441 p
To clarify the output message, programmer may also change the code like below:
void f(void *p)
{
assert(p != NULL); /* ensure p is not NULL */
/* ... */
}
In this case, assert may display:
Assertion failed on somesourcefile.c:441 p != NULL
If you had following, instead:
void f(void* p)
{
if (p == NULL)
_assert(TEXT("p is NULL!\r\n"), __FILE__, __LINE__);
}
Something you wouldn't expect will appear at the bottom of your build output window:
error: '_assert' undeclared identifier
Guess why...
ISO 9899 Standard (Programming Languages - C) has exactly one 'assert' and that one assert expects exactly one argument, and that is the the message to be displayed (usually, contains the expression that has been evaluated and returned false - but it's non of your business, anyway).
Do not try to access, *not just assert's (if one exists)*, but any internal or undocumented function directly. For example, do not do following on Windows (_WIN32, non-unicode configuration):
void f(void* p)
{
if (p == NULL)
_assert(TEXT("p is NULL!\r\n"), __FILE__, __LINE__);
}
or
#define MyNiceAssert(x) ((!!(x)) || (_asssert(#x, __FILE__, __LINE__)))
void f(void* p)
{
MyNiceAssert(p != NULL);
}
The "better" way, though I don't recommend, to roll your home grown assert could be something like this:
#ifdef _WIN32
// this is my land and don't you break into here
// WARNNOTE (ismailp): __FILE__ is ASCII, try following for UNICODE
// #define WIDEN(x) (L##x)
// #define WFILE (WIDEN(__FILE__))
// #ifdef UNICODE
// #define TFILE WFILE
// #else
// #define TFILE __FILE__
// #endif
// MyAssertReportFunction(TEXT("Message"), TFILE, __LINE__);
void MyAssertReportFunction(LPCTSTR lpszMessage, LPCTSTR lpszFile, UINT uLine)
{
// check input arguments
// calculate buffer space
// I recommend using a static MyAssert stack or heap somewhere else
extern LPTSTR lpszBuffer;
wsprintf(lpszBuffer, TEXT("Program aborted because pre/post ")
TEXT("condition has been violated.\r\n")
TEXT("Message: %s\r\n")
TEXT("File: %s\r\n")
TEXT("Line: %u\r\n"),
lpszMessage, lpszFile, uLine);
OutputDebugString(lpszBuffer);
// free/clean buffer used, if required
DebugBreak(); // preferably, you can call abort() instead
}
#define MYASSERT(x) ((!!(x)) || (MyAssertReportFunction(#x, TFILE, __LINE__)))
void CalcDate(unsigned int uYear, unsigned int uMonth, unsigned int uDay)
{
MYASSERT(uMonth < 13);
/* .. */
/* post condition */
MYASSERT(uMonth < 13);
}
#endif // _WIN32
You can use your home grown assert if you don't like your library's assert output. You can also try following:
void CalcDate(unsigned int uYear, unsigned int uMonth, unsigned int uDay)
{
assert(((uMonth < 13) && TEXT("CalcDate: Pre-condition violation; Month is greater than 12.")));
/* .. */
}
Depending on the library, as I said, it usually prints out something like below, which is more meaningful:
Assertion failed on somesourcefile.c:441
uMonth < 13 && TEXT("CalcDate: Pre-condition violation; Month is greater than 12.")
I'm not going to plot line of a horror movie to describe what could happen if you accidentally access those functions directly, but just one slightest example; _assert does not exist on Visual Studio 2005 (or may be doesn't exist with UNICODE configuration since it has _wassert), if you care about portability and future. Microsoft has never guaranteed and never guarantees that it will exist in any upcoming versions of CRT. Raymond Chen of Microsoft explains why one should not depend/rely on undocumented or internal functions:
http://blogs.msdn.com/oldnewthing/archive/2003/10/15/55296.aspx (One of my favorites)
http://blogs.msdn.com/oldnewthing/archive/2003/12/24/45779.aspx
Moral of the story;
Do
not
use
undocumented
or
internal
functions
directly,
period.









