I had a question like this on one of my exams and I'm still not too sure how to answer it. I understand that assertions are ways to test your program, however I'm not too sure what assert(0)
is checking. Is this a trick question? It will always fail, but I don't understand why. What is it checking?
Any explanation would be great, thanks.
The C++ standard defers the definition of assert
to the C standard.
” The
assert
macro puts diagnostic tests into programs; it expands to a void expression. When it is executed, if expression (which shall have a scalar type) is false (that is, compares equal to 0), the assert macro writes information about the particular call that failed (including the text of the argument, the name of the source file, the source line number, and the name of the enclosing function — the latter are respectively the values of the preprocessing macros__FILE__
and__LINE__
and of the identifier__func__
) on the standard error file in an implementation-defined format. It then calls theabort
function.
In assert(0)
the 0
is interpreted as false
, so this assertion will always fail, or fire, when assertion checking is on.
Thus it asserts that
“The execution will never reach this point.”
In practice it can be difficult to make compilers shut up about the execution reaching or not reaching a given point. Often the compiler will first complain about the execution possibly reaching the end of a function without returning a value. Adding an assert(0)
there should ideally solve that issue, but then the compiler may complain about the assert
, or not recognize that it says you're already well aware of what it tries to warn about.
One (1)possible measure then is to also throw an exception at that point:
auto foo( int x )
-> int
{
if( x == 1 ) { return 42; }
assert( 0 ); throw 0; // Should never get here!
}
Of course that double-whammy can be defined as a higher level macro. Regarding the exception type you may want to keep it as not a std::exception
, because this is not an exception intended to be caught by an ordinary catch
anywhere. Or, if you trust the standard exception hierarchy (it doesn't make sense to me, but) you can use a std::logic_error
.
To turn off assert
assertion checking you can define the symbol NDEBUG
before including <assert.h>
.
This header has special support so that you can include it multiple times, with or without NDEBUG
defined.
” A translation unit may include library headers in any order (Clause 2). Each may be included more than once, with no effect different from being included exactly once, except that the effect of including either
<cassert>
or<assert.h>
depends each time on the lexically current definition ofNDEBUG
.
A reasonable definition of the double-whammy discussed above can likewise depend on NDEBUG
with no include guard, e.g.
#include <stdexcept> // std::logic_error
#include <assert.h>
#undef ASSERT_SHOULD_NEVER_GET_HERE
#ifdef NDEBUG
# define ASSERT_SHOULD_NEVER_GET_HERE() \
throw std::logic_error( "Reached a supposed unreachable point" )
#else
# define ASSERT_SHOULD_NEVER_GET_HERE() \
do{ \
assert( "Reached a supposed unreachable point" && 0 ); \
throw 0; \
} while( 0 )
#endif
Disclaimer: While I coded that up a number of times in the early 2000s, I cooked up the code above just for this answer, and while I did test it with g++ it may not necessarily be perfect.
(1) See Basile Starynkevitch's answer for discussion of another possibility, the g++-specific intrinsic __builtin_unreachable
.