#define in #define; what happens in the preprocessor?

517 Views Asked by At

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) ?

1

There are 1 best solutions below

0
On

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:

#define X 5

adds X: (no arguments), 5 to the table.

Then:

#define Y X

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 #undefed (removed from the table), the compiler must first "paint the table entry for Y blue" and replace the token Y with the token X.

Next, the compiler must "paint the table entry for X blue" and replace the token X with the token 5.

The token 5 is not a preprocessor macro name (it can't be by definition) so the token 5 passes beyond the reach of the preprocessing phase. Now the "blue paint" is removed from the X table entry, as that's done; and then the "blue paint" is removed from the Y entry, which is also done.


If you were to write instead:

#define Y Y, Y, Y, the letter is called Y!

then the sequence, on encountering a later token Y, would be:

  1. paint entry for Y blue
  2. drop in replacement token sequence: Y , Y , Y , the letter is called Y !
  3. check each replacement token in the table -- since 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, and called 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.
  4. remove blue paint, restoring the expansion