Both C and C++ standards specify the following:
16.3.1 Argument substitution (C++11)
6.10.3.1 Argument substitution (C11)
After the arguments for the invocation of a function-like macro have been identified, argument substitution takes place. A parameter in the replacement list, unless preceded by a # or ## preprocessing token or followed by a ## preprocessing token (see below), is replaced by the corresponding argument after all macros contained therein have been expanded. Before being substituted, each argument’s preprocessing tokens are completely macro replaced as if they formed the rest of the preprocessing file; no other preprocessing tokens are available.
One can interpret this paragraph as if the standards require to:
(1) At first identify macro arguments (comma separated) and then expand all the macros contained in each argument separately,
or
(2) Expand all the macros contained in the argument list and then identify each argument.
To illustrate this, let's consider this sample code:
#define CONDITION (0)
#if (CONDITION > 0)
#define FunctionAlias(par_a, par_b, par_opt, par_c) \
FunctionName(par_a, par_b, par_opt, par_c)
#else
#define FunctionAlias(par_a, par_b, par_c) \
FunctionName(par_a, par_b, par_c)
#endif
int global_a, global_b, global_c;
#if (CONDITION > 0)
int global_opt;
#endif
void FunctionName(int a, int b, int c)
{
}
void AnotherFunction()
{
FunctionAlias(
global_a,
global_b,
#if (CONDITION > 0)
global_opt,
#endif
global_c
);
}
(1) Approach one would produce invalid code:
int global_a, global_b, global_c;
void FunctionName(int a, int b, int c)
{
}
void AnotherFunction()
{
FunctionName(global_a, global_b, #if ((0) > 0) global_opt);
}
(2) Approach 2 produces valid C code:
int global_a, global_b, global_c;
void FunctionName(int a, int b, int c)
{
}
void AnotherFunction()
{
FunctionName(global_a, global_b, global_c);
}
Which of the interpretations of the standards is the correct one?
error: embedding a directive within macro arguments has undefined behavior
. This is what GCC & Clang do. The error happens before the macro is expanded. – HolyBlackCat-pedantic-errors
, it makes GCC more standard-conformant. – HolyBlackCat#ifdef
s inside the arguments toprintf
, and some C libraries makeprintf
a macro. So we backed it down to a warning.) – zwol