If I have:
#define X 5
#define Y X
what happens in the preprocessor for that kind of thing? Is it going through the whole file and changes every X to 5, then comes back up to the next define and then changes every Y to 5 (because in the previous iteration Y got 5) ?
The C standard has a special terminology for how macros are expanded.
Macro names are, in effect, stored in a big table of "all macros defined at this time". Each table entry "macro name" on the left (and any arguments in the middle) and "expansion token-stream" on the right.
When a macro is to be expanded (because it occurs in some non-preprocessor line, or in a position in a preprocessor line in which it must be expanded -- e.g., you can
#define STDIO <stdio.h>
and then#include STDIO
), the table entry is "painted blue", and then the replacement token-stream is read (with argument expansion as also dictated by the standard).If the replacement token-stream contains the original macro name, it no longer matches, because the "blue paint" covers up the name.
When the replacement token-stream has been fully handled, the "blue paint" is removed, re-exposing the name.
Thus:
adds
X
: (no arguments),5
to the table.Then:
adds:
Y
: (no arguments),X
to the table.Somewhere later in the file, you might have an occurrence of the token
Y
. Assuming neither of the above have been#undef
ed (removed from the table), the compiler must first "paint the table entry forY
blue" and replace the tokenY
with the tokenX
.Next, the compiler must "paint the table entry for
X
blue" and replace the tokenX
with the token5
.The token
5
is not a preprocessor macro name (it can't be by definition) so the token5
passes beyond the reach of the preprocessing phase. Now the "blue paint" is removed from theX
table entry, as that's done; and then the "blue paint" is removed from theY
entry, which is also done.If you were to write instead:
then the sequence, on encountering a later token
Y
, would be:Y
blueY
,
Y
,
Y
,
the
letter
is
called
Y
!
Y
is painted blue those don't match, and,
cannot match, so those are all passed on to the rest of the compiler;the
,letter
,is
, andcalled
must be checked but are probably not in the table and hence passed on;Y
is still painted blue so does not match and is passed on, and!
cannot match and is passed on.