Kevin Dong
Kevin Dong

Reputation: 5369

How does C preprocessor actually work?

I made the code snippet simpler to explain

// Example 1

#define sum2(a, b) (a + b)
#define sum3(a, b, c) (sum2(a, sum2(b, c)))

sum3(1, 2, 3)    // will be expanded to ((1 + (2 + 3)))


// Example 2

#define score student_exam_score
#define print_score(student_exam_score) printf("%d\n", score)
#undef  score

print_score(80); // will be expanded to printf("%d\n", score);
                 // but not printf("%d\n", 80); that I expect

The first one is intuitive, and that kinds of codes exists in several places such as finding the maximum or minimum number. However, I want to use that technique to make my code clean and easy to read, so I replace the some words in a macro with a shorter and more meaningful name.

AFAIK, C preprocessor runs only once per compilation unit and only performs string replacement, but why print_score cannot be expanded to printf("%d\n", 80);?

This is the replacement procedure I guess:

#define score student_exam_score
#define print_score(student_exam_score) printf("%d\n", score)
#undef  score

print_score(80);

//  --> 

#define score student_exam_score  // runs this first
#define print_score(student_exam_score) printf("%d\n", student_exam_score)  // changed
#undef  score

print_score(80);

//  --> 

#define score student_exam_score
#define print_score(student_exam_score) printf("%d\n", student_exam_score)  // then this
#undef  score

printf("%d\n", 80);  // changed

Upvotes: 5

Views: 127

Answers (1)

Tom Karzes
Tom Karzes

Reputation: 24102

It's a sequencing issue. First the macros are defined, and score is undefined before it is ever used. Then, when print_score is expanded, it first substitutes all instances of student_exam_score, of which there are none. It then rescans the result, looking for further macros to expand, but there are none since score has been undefined and is no longer available.

Even if you moved #undef score down below the reference to print_score, it still wouldn't work since parameter substitution only happens once (score would be expanded but student_exam_score would not).

Note that score is not substituted into the body of print_score at the time is it defined. Substitution only happens when the macro is instantiated, which is why #undef score results in the score macro having no effect whatsoever.

These examples will make it clearer. First, consider the following:

#define foo bar
#define baz(bar) (foo)
baz(123)

This is expanded as follows:

    baz(123)
->  (foo)
->  (bar)

Expansion stops here. Parameter substitution was done before foo was expanded, and does not happen again.

Now consider the following:

#define foo bar
#define baz(bar) (foo)
#undef foo
baz(123)

This is expanded as follows:

    baz(123)
->  (foo)

Expansion stops here because foo is no longer defined. Its earlier definition had no effect on the definition of baz, because macro substitution does not happen when macros are defined. It only happens when they are expanded.

Upvotes: 3

Related Questions