Is the standard C assert(e)
macro permitted to evaluate e
multiple times? What about C++11 or later? I don't see any guarantees in the Open Group spec, and the answer isn't apparent to me from some searching (1, 2).
Context: could func()
be called multiple times in assert(func() != NULL)
?
Yes, I already know this is a bad idea for other reasons: as the glibc manual points out, the argument of assert()
won't be evaluated at all if NDEBUG
is defined. However, assuming NDEBUG
is not defined, is there any guarantee on the maximum number of times e
is evaluated?
Question prompted by this one.
In the C11 standard (ISO/IEC 9899:2011), §7.1.4 Use of library functions says:
Each of the following statements applies unless explicitly stated otherwise in the detailed descriptions that follow: …
Any invocation of a library function that is implemented as a macro shall expand to code that evaluates each of its arguments exactly once, fully protected by parentheses where necessary, so it is generally safe to use arbitrary expressions as arguments.186) Likewise, those function-like macros described in the following subclauses may be invoked in an expression anywhere a function with a compatible return type could be called.187)
186) Such macros might not contain the sequence points that the corresponding function calls do.
187) Because external identifiers and some macro names beginning with an underscore are reserved, implementations may provide special semantics for such names. For example, the identifier
_BUILTIN_abs
could be used to indicate generation of in-line code for theabs
function. Thus, the appropriate header could specify#define abs(x) _BUILTIN_abs(x)
for a compiler whose code generator will accept it. In this manner, a user desiring to guarantee that a given library function such as
abs
will be a genuine function may write#undef abs
whether the implementation’s header provides a macro implementation of
abs
or a built-in implementation. The prototype for the function, which precedes and is hidden by any macro definition, is thereby revealed also.
The preamble in §7.2 Diagnostics <assert.h>
says:
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.
And section §7.2.1.1 The assert
macro says:
The
assert
macro puts diagnostic tests into programs; it expands to a void 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.191) The message written might be of the form:
Assertion failed:
expression
, function
abc
, file
xyz
, line
nnn
.
So much for the verbiage of the standard — how does that translate in practice?
A lot hinges on the interpretation of the statement:
If assert
is regarded as a function that is implemented via a macro, then its argument shall be evaluated just once (the conversion to string is a compile-time operation that does not evaluate the expression).
If assert
is regarded as 'not a function' (because it is explicitly a macro), then the restriction quoted doesn't necessarily apply to it.
In practice, I'm sure that the intent is that the expression argument to assert
should only be evaluated once (and that only if NDEBUG
was not defined when the <assert.h>
header was last included) — so I'd regard it as being constrained as if it was a function that is implemented via a macro. I'd also regard any implementation that implemented assert
in such a way that the expression was evaluated twice as defective. I'm not certain that the quoted material supports that, but it is all the relevant material I know of in the standard.