The C11 standard says (and other versions of C, and C++, say similarly):
A preprocessing directive of the form # define identifier replacement-list new-line
defines an object-like macro that causes each subsequent instance of the macro name to be replaced by the replacement list of preprocessing tokens that constitute the remainder of the directive. The replacement list is then rescanned for more macro names as specified below.
However it also says in another part (thanks to rici for pointing this out).
The preprocessing tokens within a preprocessing directive are not subject to macro expansion unless otherwise stated.
So a subsequent instance of the macro name which is found inside another #define
directive is actually not replaced.
Your line #define FOO NUM
defines that when the token FOO
is later found (outside of another #define
directive!), it will be replaced by the token NUM
.
After a token is replaced, rescanning occurs, and if NUM
is itself a macro, then NUM
is replaced at that point. (And if whatever NUM
expands to contains macros , then that gets expanded , and so on).
So your sequence of steps is actually:
NUM
defined as 10
FOO
defined as NUM
NUM
undefined and re-defined as 20
FOO
expands to NUM
- (rescan)
NUM
expands to 20
This behaviour can be seen in another common preprocessor trick, to turn the defined value of a macro into a string:
#define STR(X) #X
#define STR_MACRO(X) STR(X)
#define NUM 10
puts( STR_MACRO(NUM) ); // output: 10
If we had written puts( STR(NUM) )
then the output would be NUM
.
The output of 10
is possible because, as before, the second #define
here does not actually expand out STR
. So the sequence of steps in this code is:
STR(X)
defined as #X
STR_MACRO(X)
defined as STR(X)
NUM
defined as 10
STR_MACRO
and NUM
are both expanded; the result is puts( STR(10) );
- (Rescan result of last expansion)
STR(10)
is expanded to "10"
- (Rescan result of last expansion) No further expansion possible.