When the c preprocessor runs an #if
/#elif
preprocessing directive, it performs 4 operations on the tokens that directly follow:
- Replace every occurrence of
defined {identifier}
with1
if{identifier}
is defined,0
otherwise. - Invoke all macros.
- Replace every remaining identifier with
0
. - Parse and evaluate the result as a
constant-expression
.
Now, it's pretty clear from the standard (c99, 6.10.1) that steps 3 and 4 actually happen in that order, and after 1 and 2 are completed. But I can't find any clarification on the order of 1 and 2.
From some limited testing I did, it seems that gcc executes steps 1 and 2 based on the ordering of the tokens - in defined MACRO
, the defined
executes first, but in MACRO(defined ID)
the macro does.
Is this behavior required by the standard? Implementation-defined? Undefined?
CodePudding user response:
Your step 2 is performed first. The order is steps 2, 1, 3, 4:
C 2018 6.10.1 4 says [emphasis mine]:
Prior to evaluation, macro invocations in the list of preprocessing tokens that will become the controlling constant expression are replaced (except for those macro names modified by the
defined
unary operator), just as in normal text…
6.10.1 1 says that the controlling expression of an #if
or #elif
shall be an integer constant expression which may additionally contain the expressions defined identifier
or defined ( identifier )
which:
… evaluate to 1 if the identifier is currently defined as a macro name (that is, if it is predefined or if it has been the subject of a
#define
preprocessing directive without an intervening#undef
directive with the same subject identifier), 0 if it is not.
Thus, first macro replacement is performed, per 6.10.1 4, and later the evaluation of the expression is performed.
Note that, in spite of the fact that macro replacement occurs first, if it generates defined
tokens, they are not necessarily evaluated, because 6.10.1 4 goes on to say:
… If the token
defined
is generated as a result of this replacement process…, the behavior is undefined.
Then your step 3 occurs, again per 6.10.1 4:
… After all replacements due to macro expansion and the
defined
unary operator have been performed, all remaining identifiers (including those lexically identical to keywords) are replaced with the pp-number0
, and then each preprocessing token is converted into a token…
Then the controlling expression is evaluated, your step 4:
… The resulting tokens compose the controlling constant expression which is evaluated according to the rules of 6.6…