00001 /* assert.h
00002 Copyright (C) 2001, 2003 Free Software Foundation, Inc.
00003 Written by Stephane Carrez (stcarrez@nerim.fr)
00004
00005 This f
__assert
is part of the implementation; in this case, a function in the library which will be called in case of assertion failure. And the (void)
is simply to shut up compiler warnings about the unused results of the ||
operator.
Look at this line:
extern void __assert (const char *msg, const char *file, int line);
__assert
is function that takes an assertion message, a file name and a line number as arguments. Basically, this is the method that prints out the error message and terminates the program when the assertion failed.
Then look at the macro definition above:
#define assert(EX) (void)((EX) || (__assert (#EX, __FILE__, __LINE__),0))
It defines the assert(EX)
macro so, it first checks the EX expression and (because of the short-circuit operation of the C++ ||
operator) only if it fails, it calls the __assert
function and passes the failed assertion exception as a string, and the exact location of the assert()
method call in your source files. With this preprocessor trickery the assertion library achieves that when you type the following in your program
assert(a == 0);
and your assertion fails during the program run, you get the detailed
Assertion failed: a == 0 at program.c, line 23
error message that helps you to identify the exact location where the assertion was failing in your code.
The (void)
part is just for make sure that the compiler won't put up some warnings about the unused result of the (EX) || 0
expression, see the other answers, the guys explained it well.
The remaining preprocessor define NDEBUG
is used to turn of assertion generation at all compile-time, you your resulting executable will be smaller and faster.
Almost...
Consider: assert( a == 0 );
This is expanded to
(void)((a == 0) || (__assert (#a == 0, __FILE__, __LINE__),0))
If you have the expression (x || y)
- In this case both x and y evaluate as bools, so if 'a' evals to 0, the definition of || says to try the next bool in line, ie 'y'
So - if your assertion is false, (__assert (#a == 0, __FILE__, __LINE__),0)
gets evaluated, which means __assert()
gets called.
Why the (__assert(), 0) ?? __assert is a function defined as void __assert()
- well ... most of the time. see http://www.opensource.apple.com/source/Libc/Libc-825.26/include/assert.h for one set of assert() macros - note that all of them end up calling a function ...
The comma operator lets you do two things in the same statement, ie i++, j++
- but remember an expression has to evaluate to some value - in this case to the "0" - so the entire statement evaluates to (void)(0 || 0)
which is a valid expression. As a side effect, your expression is evaluated and possibly a function gets called.
Note in (void)(0 || 0)
the first 0 is from your failed assertion. This may be created at compile time if your assertion evaluates to something the compiler can create as a constant, or an expression that gets evaluated, ie (void)((a == 0) || 0)
note the comma ",0" is for really pedantic compilers - I usually don't see it. But the (a || __assert())
is very common. You could write the macro as
#define assert( x ) { if( ! (x)) __assert(.....); }
It suppresses compiler warnings about unused values or variables.
Also note the comma operator on the right, which makes both sides of the ||
something that's convertible to bool.
__assert
is an internal function that will presumably print a message and implement the required assertion behaviour (i.e. call abort()
).