Assert

From GPWiki
Jump to: navigation, search
40px-broken-icon.png   This page has broken markup.
If you fix this problem, please remove this banner.

Checking for strange situations in your code is always a matter of weighting robustness gains versus performance losses. You can check everything all the time, but then your code would get bloated and slow.

Assertions (as seen in C) provide a partial solution to this problem. They rely on the concepts of having separate 'debug builds' and 'release builds'. An assert is a check that is made in debug, but not in release mode. The power of this is that you can check everything you are not 100% certain about without bloating up the final program.

Using assert

Example (C):

#include <assert.h>
 
void Handle_Object(Object* pointer)
{
  assert(pointer != NULL);
  // do stuff
}

This function requires it's argument to be a valid pointer, and checks to make sure no one accidentially passes a NULL pointer. If NULL is passed it terminates the program with a message something like "Assertion (pointer != NULL) in handle.c line 6 failed.". Not very pretty.

That brings us to an important property of assertions. They are used to check programmer errors, and not stuff that can go wrong in release mode. They help during testing the code by blowing up with a clear message instead of going on and causing an obscure segfault or something. Stuff that can go wrong in release mode, invalid input for example, should be handled a lot more gracefully.

Create Your Own asserts

You can create your own asserts. The implementation of assert() differs between compilers and platforms, but generally it is implemented in the file assert.h using a macro. You can create your own asserts using this macro as a template. Here are some useful variations for use with Microsoft Visual C++ and Win32.

Assert that a value is in a certain range

This macro asserts that the value v is between the values l and h (inclusive).

#define assert_limits( l, v, h )                                                                  \ 
    do                                                                                            \ 
    {                                                                                             \ 
        if ( !( (l) <= (v) && (v) <= (h) ) &&                                                     \ 
             ( _CrtDbgReport( _CRT_ASSERT, __FILE__, __LINE__, NULL, #l " <= " #v " <= " #h ) ) ) \ 
        {                                                                                         \ 
            _CrtDbgBreak();                                                                       \ 
        }                                                                                         \ 
    } while (0)

Assert that an array index is valid

This macro asserts that the value i is a valid array index for the array a, which must be an array and not a pointer.

#define assert_array_index_valid( a, i )                                                                    \
    do                                                                                                      \
    {                                                                                                       \
        if ( !( 0 <= (i) && (i) < sizeof(a)/sizeof(*(a)) ) &&                                               \
             ( _CrtDbgReport( _CRT_ASSERT, __FILE__, __LINE__, NULL, "0 <= " #i " <= elements in " #a ) ) ) \
        {                                                                                                   \
            _CrtDbgBreak();                                                                                 \
        }                                                                                                   \
    } while (0)

Assert that a value is a power of two

This macro asserts that the value i is 0 or a power of two.

#define assert_power_of_two( i )                                                                   \
    do                                                                                             \
    {                                                                                              \
        if ( !( ( (i) & ( (i) - 1 ) ) == 0 ) &&                                                    \
             ( _CrtDbgReport( _CRT_ASSERT, __FILE__, __LINE__, NULL, #i " is a power of two" ) ) ) \
        {                                                                                          \
            _CrtDbgBreak();                                                                        \
        }                                                                                          \
    } while (0)

Assert that a value is aligned

This macros asserts that the value v is aligned (a multiple of) the value n.

#define assert_aligned( v, n )                                                                      \
    do                                                                                              \
    {                                                                                               \
        if ( !( (v) % (n) == 0 ) &&                                                                 \
             ( _CrtDbgReport( _CRT_ASSERT, __FILE__, __LINE__, NULL, #v " is " #n "-aligned"  ) ) ) \
        {                                                                                           \
            _CrtDbgBreak();                                                                         \
        }                                                                                           \
    } while (0)