13
00001 /* assert.h
00002    Copyright (C) 2001, 2003 Free Software Foundation, Inc.
00003    Written by Stephane Carrez (stcarrez@nerim.fr)       
00004 
00005 This file is free software; you can redistribute it and/or modify it
00006 under the terms of the GNU General Public License as published by the
00007 Free Software Foundation; either version 2, or (at your option) any
00008 later version.
00009 
00010 In addition to the permissions in the GNU General Public License, the
00011 Free Software Foundation gives you unlimited permission to link the
00012 compiled version of this file with other programs, and to distribute
00013 those programs without any restriction coming from the use of this
00014 file.  (The General Public License restrictions do apply in other
00015 respects; for example, they cover modification of the file, and
00016 distribution when not linked into another program.)
00017 
00018 This file is distributed in the hope that it will be useful, but
00019 WITHOUT ANY WARRANTY; without even the implied warranty of
00020 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00021 General Public License for more details.
00022 
00023 You should have received a copy of the GNU General Public License
00024 along with this program; see the file COPYING.  If not, write to
00025 the Free Software Foundation, 59 Temple Place - Suite 330,
00026 Boston, MA 02111-1307, USA.  */
00027 
00028 #ifndef _ASSERT_H
00029 #define _ASSERT_H
00030 
00031 #ifdef NDEBUG
00032 # define assert(EX)
00033 #else
00034 # define assert(EX) (void)((EX) || (__assert (#EX, __FILE__, __LINE__),0))
00035 #endif
00036 
00037 #ifdef __cplusplus
00038 extern "C" {
00039 #endif
00040 
00041 extern void __assert (const char *msg, const char *file, int line);
00042 
00043 #ifdef __cplusplus
00044 };
00045 #endif
00046 #endif

The question is: what is for the "(void)" on line 34 and what is __assert?

Narek
  • 38,779
  • 79
  • 233
  • 389

4 Answers4

18

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.

xashru
  • 3,400
  • 2
  • 17
  • 30
buc
  • 6,268
  • 1
  • 34
  • 51
  • 1
    All right, perfect, thanks for detailed explanation. Only two questions: 1) Why (__assert (#EX, __FILE__, __LINE__),0) it is used ",0" and 2) Why (what mechanism) suppresses the warning of the compiler when you cast bool to void? Is it because void is nothing??? – Narek Mar 14 '12 at 12:08
  • 5
    1) The [comma operator](http://en.wikipedia.org/wiki/Comma_operator) (`,`) first executes the expression on its left (`__assert` call) then the one on its right (literal `0`) and returns the result of the latter one. It is needed because the `||` operator expects a boolean-compatible operand, but the `__assert` function returns `void`. – buc Mar 15 '12 at 08:19
  • 5
    2) Imagine a statement `(a == 3) || (0);` alone on a line. It does not make much sense to perform a comparison and then do nothing with the result. The compiler also recognizes this and suspects that you have forgotten to complete the statement and warns you about it. By casting the whole expression to `void`: `(void)((a == 3) || (0))` you tell the compiler that this expression has no sensible result value (like a call to a `void`-returning function would not have also), so it won't complain about it. – buc Mar 15 '12 at 08:25
8

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

James Kanze
  • 150,581
  • 18
  • 184
  • 329
2

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

Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
1

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(.....); }
Steve
  • 7,171
  • 2
  • 30
  • 52