The C Standard, subclause 7.1.4 paragraph 1, states [ISO/IEC 9899:2011]:
Any function declared in a header may be additionally implemented as a function-like macro defined in the header, so if a library function is declared explicitly when its header is included, one of the techniques shown below can be used to ensure the declaration is not affected by such a macro. Any macro definition of a function can be suppressed locally by enclosing the name of the function in parentheses, because the name is then not followed by the left parenthesis that indicates expansion of a macro function name. For the same syntactic reason, it is permitted to take the address of a library function even if it is also defined as a macro.185
185) This means that an implementation shall provide an actual function for each library function, even if it also provides a macro for that function.
However, the C Standard enumerates specific exceptions enumerates several instances in which the behavior of accessing an object or function expanded to be a standard library macro definition is undefined. The macros are assert
, errno
, math_errhandling
, setjmp
, va_start
, va_arg
, va_copy
, and va_end
. These cases are recorded in Annex J, subclause J.2, items 110, 114, 122, 124, and 138. Programmers should never attempt to access anything underlying any of these macros.
Noncompliant Code Example (assert
)
In this example, the standard standard assert()
macro is suppressed in favor of calling a user-defined assertan attempt to pass it as a function pointer to the execute_handler()
function.Suppose the custom <myassert.h>
declares a function assert()
that does nonstandard verification, and the standard <assert.h>
defines an assert
macro as required by the standard: Attempting to suppress the assert()
macro is undefined behavior.
Code Block | ||||
---|---|---|---|---|
| ||||
#include <assert.h> #include "myassert.h"typedef void (*handler_type)(int); void fullAssert(execute_handler(handler_type handler, int evalue) { assert(e > 0); /* Invoke standard library assert() */ (assert)(e > 0); /* * assert() macro suppressed; calling * function assert(). */ } |
...
handler(value);
}
void func(int e) {
execute_handler(&(assert), e < 0);
} |
Compliant Solution (assert
)
The programmer should place nonstandard verification in a function that does not conflict with the standard library macro assert
—for example, myassert()
In this compliant solution, the assert()
macro is wrapped in a helper function, removing the undefined behavior:
Code Block | ||||
---|---|---|---|---|
| ||||
#include <assert.h> #include "myassert.h"typedef void (*handler_type)(int); void fullAssert(execute_handler(handler_type handler, int evalue) { handler(value); } static void assert(e > 0); /* Standard library assert() */ myassert(e > 0); /* Well-defined custom assertion function */ } _handler(int value) { assert(value); } void func(int e) { execute_handler(&assert_handler, e < 0); } |
Noncompliant Code Example (Redefining errno
)
...
Bibliography
ISO/IEC 9899:2011 | Subclause 7.1.4, "Use of Library Functions" |