问题
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.
回答1:
It will always fail. That's pretty much it. It will fail always for the same reason that "assert(x == 5)" will succeed whenever x = 5.
If you're asking for an application then you would put it in code blocks that really shouldn't happen.
switch(suit) {
case CLUB:
case DIAMOND:
case HEART:
case SPADE:
// ...
default:
assert(0);
}
回答2:
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
.
回答3:
Yes, it will always fail.
assert(0)
or assert(false)
is usually used to mark unreachable code, so that in debug mode a diagnostic message is emitted and the program is aborted when the supposedly unreachable is actually reached, which is a clear signal that the program isn't doing what we think it is.
回答4:
In addition to other answers (notably this one), if you are using a recent GCC (or Clang), you might consider using some GCC builtin, notably __builtin_unreachable()
instead of assert(0)
.
There are some differences: first, assert
can be disabled with -DNDEBUG
. And __builtin_unreachable
will change the way the compiler is optimizing your code.
Of course some compilers don't know about __builtin_unreachable
.
And you could also consider calling some [[noreturn]]
C++ function (in C++11 or better) - or __attribute__((noreturn)) for GCC, such as abort()
BTW, assert(0)
is not exactly like throwing some exception (since exceptions can be caught)
来源:https://stackoverflow.com/questions/34236653/what-does-assert0-mean