C/C++ Assertions and Defining Your Own Assert Macro

Why should I use assert???

The assert macro defined in <assert.h> is a C programmer’s best friend. Really. With the plethora of potential pitfalls in the wild world of C, assert presents a simple and lightweight way of assuring that various conditions in your program hold true so that you can develop in a defensive manner – after all, we’re taking nothing for granted and taking no prisoners 😉

Runtime assertions should be used judiciously. They establish conditions which absolutely must be true, because if they aren’t true, then there’s something seriously wrong with the logic of your program (read: you botched something somewhere). Consequently they work quite nicely for verifying function/method pre-conditions during development. Assertions are NOT intended for dealing with user/system errors such as invalid input, failure to open a file or a loss in internet connectivity.

Another great thing about asserts is that they can be compiled out of code simply by defining NDEBUG. That can also result in some very nasty surprises if any of the code you’re asserting causes side-effects. Imagine a scenario where you’re developing in debug mode and you have some code like this – AttachParachute() of course returns a boolean value.

assert(skyDiver->AttachParachute());
skyDiver->JumpFromPlane();

To your delight, after typing your last line of code, you feed it to your machine, and everything is hunky dory and no-one dies. Later on, you attempt a release build only to find that your skydiver remains at terminal velocity for a little longer than expected. After the lugubrious feelings subside, you’re left wondering why fate has it in for you. “But my code ran perfectly before! And none of my assertions are failing!” It’s crucial to understand that many release builds define NDEBUG which means that assert statements and anything inside them will not exist in the binary… your skydiver never had his parachute attached! Moral of the story is, assert results of operations, not operations themselves.

All the cool kids have their own assert macros… I want one too!!!

Ok, so maybe my definition of ‘cool’ is completely skewed here, but that’s quite beside the point… Regular C assert is just fine and dandy but there are many possible reasons for wanting to write a custom macro. Maybe you want to log failed assertions in a project specific manner rather than simply printing to stderr? Maybe you’re working in an embedded environment and stderr isn’t available (and you’d rather emit the assertion details in morse code blips)? Maybe you want to support custom handlers since your unit-testing framework doesn’t handle failed asserts gracefully?

The reason I initially defined my own assert macro is rather foolish in retrospect. I was working on a static library and a DLL, as well as a console app which uses both of them. I noticed some strange behaviour with regards to how my asserts were reporting file/line data – all of the failed assertions were correctly halting execution and spawning dialogs but only sometimes was the assertion location data being reported in that dialog. Had it not been for the reams of console output, I probably would have noticed that the assertion data was being printed to the console in the cases when it wasn’t being sent to the dialog. But that moment of enlightenment came only after I’d already hacked together a quick assert macro. As it turns out, how assertion data is reported in MSVC depends on the app type as explained here. Both console apps and Windows apps spawn dialogs, console apps report only to stderr, Windows apps report only to their dialogs.

Sample C++ Assert Macro

#ifndef NDEBUG
  #include <cassert>
  #define UL_ASSERT(condition)
  {
      if(!(condition))
      {
          std::cerr << "Assertion failed at " << __FILE__ << ":" << __LINE__;
          std::cerr << " inside " << __FUNCTION__ << std::endl;
          std::cerr << "Condition: " << #condition;
          abort();
      }
  }
#else
  #define UL_ASSERT(condition) (condition)
#endif

Here is a skeleton C++ assert macro which isn’t too different to the one I originally wrote. There are several points to note:

  • Failed assertion data is always printed only to stderr/cerr (but a dialog box will still be spawned regardless of app type… at least in MSVC).
  • If NDEBUG is defined, rather than effectively compiling out UL_ASSERTs (as happens with regular C asserts), a different version is used instead; one which simply evaluates the condition and doesn’t verify it. This protects against the code-with-side-effects problem I mentioned above. And you needn’t worry about unnecessary condition evaluations resulting in code bloat or a performance hit provided that your compiler is smart enough to optimise out simple conditions which don’t affect dataflow (most compilers are).
  • The macro contents are contained within an extra pair of braces to ensure that the IF clause contained within a macro expansion cannot conflict with a subsequent ELSE clause.
  • The condition is enclosed in parentheses in accordance with good macro practices (no, that’s not an oxymoron ;)) to ensure that an assertion like UL_ASSERT(2 < 0) expands to if(!(2 < 0))… rather than the erroneous if (!2 < 0)… which yields entirely different results.

And that about wraps up this post. I hope someone finds it useful. Feel free to reuse and modify the skeleton assert for your own purposes. And feel free to point out any mistakes I may or may not have made 😛

This entry was posted in C, C++ and tagged , , , , , , , , . Bookmark the permalink.

1 Response to C/C++ Assertions and Defining Your Own Assert Macro

  1. tadele says:

    we are Negros from the hood and are breaking down C++

Leave a Reply to tadele Cancel reply

Your email address will not be published. Required fields are marked *