1

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

2
  • Did you try it? It shouldn't take more than half a minute. What happened? Commented Dec 8, 2013 at 21:23
  • 1
    compile your code with gcc -E and you can see what kind of code that preprocessor generate Commented Dec 8, 2013 at 21:26

1 Answer 1

6

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
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.