Dear C++ Community,
I have recently came across an interesting problem that might be
related to a subject for improvement in the C++ Standard. It is
related to macro replacement, so rather an "old C stuff". But not
only C++ shares this features with C, but also C++ Standard shares
the wording with C standard in this area, especially below
paragraph.
16.3.1 Argument
substitution
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 standard required to:
or
In fact, the first approach is represented by one of the most widely-used commercial static analyzers (for C), while the second one is apparently applied by GCC as well as some other commercial compiler vendors.
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
);
}
is transformed by GCC preprocessor to 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)
;
}
However, the preprocessor embedded in the analyzer produces:
/* 12 */ int
global_a, global_b, global_c;
/* 17 */ void FunctionName(int a, int b, int c)
/* 18 */ {
/* 19 */ }
/* 21 */ void AnotherFunction()
/* 22 */ {
/* 30 */ FunctionName(global_a, global_b, #if ((0) > 0)
global_opt);
/* 31 */ }
1. What is your opinion on which of the interpretations above is in line with the intentions of the authors of the quoted paragraph?
2. Do you share my impression that the paragraph is not precise enough for the reader to strongly decide which approach is the right one?
Thank you in advance for your answers.
Best regards,
Marcin