C++ assert implementation in assert.h

旧街凉风 提交于 2019-11-29 03:49:30

Look az 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.

__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.

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()).

user2913342

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(.....); }
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!