5

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
4
  • print_score(80); => printf("%d\n", score) => printf("%d\n", student_exam_score), so that's the issue. Commented May 15, 2016 at 8:36
  • @BlackMamba Won't print_score(student_exam_score) printf("%d\n", score) be replaced with print_score(student_exam_score) printf("%d\n", student_exam_score) first? Commented May 15, 2016 at 8:37
  • 1
    "C preprocessor runs only once per compilation unit" and "why print_score cannot be expanded to printf("%d\n", 80);?" The latter is exactly because of the former. Commented May 15, 2016 at 8:38
  • @Keivin Dong I think it is releated to the order of expland MARCO Commented May 15, 2016 at 8:40

1 Answer 1

3

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.

Sign up to request clarification or add additional context in comments.

7 Comments

Why is score undefined? I am not sure whether preprocessing has issue about undefined.
It's a sequencing issue. #undef score undefines score before it has ever been used. See the last paragraph in my answer, which I just added.
#undef exists just for not impacting the following code.
I understand what you want. But it doesn't work the way you think it does. score will not be expanded in the body of print_score until after print_score has been instantiated, but by then score is no longer defined. If you look at the preprocessor output, you will understand. But it doesn't really matter, since even if score were defined, it would still stop short of substituting the paremeter.
I start using cpp for checking the only-preprocessed output. I am still confused about why the first one works, but not mine. Isn't the first one also faced the problem?
|

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.