Skip navigation.

Ambassador

The Royal C++ Embassy

Let's obey standards

, ,

One should always assert the pre - and sometimes post - conditions in the code so that any problem that arises during debug can be caught, this hopefully saves a lot reputation of your company.

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
.

Mind-bogglingly interesting number was not 9!(N)RVO - Good, bad, or ugly?

Write a comment

You must be logged in to write a comment. If you're not a registered member, please sign up.

Download Opera, the fastest and most secure browser
December 2009
S M T W T F S
November 2009January 2010
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31