Reputation: 4817
Environment:
$ g++ --version
g++ (Ubuntu 7.4.0-1ubuntu1~18.04) 7.4.0
It is known that function-like macro assert
for debugging can be disabled with NDEBUG
defined before the include of assert.h
(cassert
). However, reading /usr/include/assert.h
in my environment, I found the code below.
#if defined __cplusplus && __GNUC_PREREQ (2,95)
# define __ASSERT_VOID_CAST static_cast<void>
#else
# define __ASSERT_VOID_CAST (void)
#endif
#ifdef NDEBUG
# define assert(expr) (__ASSERT_VOID_CAST (0))
# ifdef __USE_GNU
# define assert_perror(errnum) (__ASSERT_VOID_CAST (0))
# endif
#else /* Not NDEBUG. */
So, even with NDEBUG
, assert
is expanded into some value and thus affect the performance insignificantly but certainly (if no optimization occurs after the preprocess step). Since C++ standard allows function-like macro with empty value, it seems
#ifdef NDEBUG
#define assert(expr)
#endif
would be a good implementation.
Is there any reason why non-empty value should be the option?
Upvotes: 9
Views: 1679
Reputation: 754030
One reason that the macro has a value when NDEBUG
is defined is because the C standard requires that it has one — it even stipulates what it shall be.
¶1 The header
<assert.h>
defines theassert
andstatic_assert
macros and refers to another macro,NDEBUG
which is not defined by
<assert.h>
. IfNDEBUG
is defined as a macro name at the point in the source file where<assert.h>
is included, theassert
macro is defined simply as#define assert(ignore) ((void)0)
The
assert
macro is redefined according to the current state ofNDEBUG
each time that<assert.h>
is included.¶2 The
assert
macro shall be implemented as a macro, not as an actual function. If the macro definition is suppressed in order to access an actual function, the behavior is undefined.…
Synopsis
#include <assert.h> void assert(scalar expression);
Description
¶2 The
assert
macro puts diagnostic tests into programs; it expands to avoid
expression. When it is executed, ifexpression
(which shall have a scalar type) is false (that is, compares equal to 0), theassert
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 stream in an implementation-defined format.191) It then calls theabort
function.Returns
¶3 The
assert
macro returns no value.191) The message written might be of the form:
Assertion failed: expression, function abc, file xyz, line nnn.
The C++11 standard says (§19.3 Assertions) says:
The header
<cassert>
… provides a macro for documenting C++ program assertions and a mechanism for disabling the assertion checks.…
The contents are the same as the Standard C library header
<assert.h>
.
So the same rules apply to C++ as to C. The C++ standard doesn't explicitly call out the differences between the C++ static_assert
and the C _Static_assert
(and the definition of static_assert
as _Static_assert
in the C version of the <assert.h>
header). The net result is much the same, though.
Upvotes: 10