The basic premise behind an
assert(bool_t value) is that the macro/function checks to make sure that value is true. The coder adds the checks where the expected result should be true. (i.e. don’t use them as an if statement). If the value is not true (i.e. false), the software/firmware takes specific action.
For a software application, this “specific action” may be printing out the filename and line number the
assert() was raised in, and then exiting the application. For a firmware application, this may be printing out the filename and line number the
assert() was raised in, and then restarting (it does not make sense to “quit” in a firmware environment).
Assertions refer to the use of both the standard C library
assert() macro, and the use of similar user-defined macros.
If you are looking for a full-blown
assert() example, check out the compilable/testable
assert() code snippet at
A Simple assert() Using A Macro
assert() is usually defined in C using a macro (rather than a function), due to the ability of automatically keep track of things such as the filename and line number that the
assert() was written on.
A basic assert macro could have the following definition:
Note that the ternary operator is used here instead of an if statement.
AssertRaised() is a function you have to write that will handle any raised
assert()’s. It would have the following declaration:
A Note On FILE and LINE
__LINE__ are special Standard Predefined Macros as defined by the C language specifications. For more info, see the
File Names And Line Numbers section of the Preprocessor page.
__LINE__ can be removed from the macro in flash constrained embedded systems (storing the filename strings can take up a decent amount of flash).
Note that use of
__FILE__ may not take up as much flash memory as you think, as most compilers with any sort of optimisation turned on will collate all string literals which are exactly the same into one (i.e. all the the
__FILE__ pointers in the same file will point to the same string literal).
Are there any other useful preprocessor keywords? How about
__func__? This gets replaced with a const char * that contains the name of the current function the macro is in.
Printing The Failed assert() Condition
Even more useful than just having the filename and line number is also printing the expression which caused the failed assert() . Luckily, this is easy to do, using the preprocessor stringification symbol, #.
The function which handled the failed
assert() would then have the following declaration:
Note that this would consume much more flash memory than
__FILE__ alone would, as rarely any of the
const char * expression string literals would be the same.
assert() checks should NOT have any side effects. That is, they should only do a boolean comparison between two variables/values. You should not embed assignments or function calls inside
assert() checks. This is to prevent the logic of your application changing when enabling/disabling
assert() macro can be re-written to stop developers from writing
assert()’s with side effects. This can be done by making clever use of the C comma operator (note that this is not the same as the comma used as a separator between variables in a function call).
Is using the GCC compiler, and you write an assert with side effects, you should get the following error:
Note that I was using gcc-5.1 when I was presented with this error.
Complete Code Example
I have written a working
assert() example at
http://ideone.com/CSX6wN. It employs all of the functionality described above, including filename and line number reporting, expression printing, and syntax which disallows the use of assignments or function calls within the parameter passed to
Assert With printf() Style Messages
The below macro allows you to use assert with
printf() style messages:
A working example of the above code can be found at https://ideone.com/DD1PJs.
Assert Yourself, by Niall Murphy, is a good read about using the assert() macro.
This work is licensed under a Creative Commons Attribution 4.0 International License .