Recently I am learning some advanced programming skills in metaprogramming, and I have met some kind of problem understanding the execution of preprocessing commands in C . Originnal I assumed preprocessing commands are executed in the order they are in C codes. However, given the following code, it does not produce expected result.
#include <cstdio>
void a() {
printf("a\n");
}
void b() {
printf("b\n");
}
void c() {
printf("c\n");
}
int main() {
#define a b
#define c a
a(); // 1. a() -> b()
b();
c(); // 2. c() -> a()
#undef c
#undef a
return 0;
}
/*
if #define is executed in order, then expect
b
b
a
however get
b
b
b
*/
I thought it would first execute the substitution of
#define a b
to produce
int main() {
b();
b();
c();
return 0;
}
then execute
#define c a
to produce
int main() {
b();
b();
a();
return 0;
}
However, when I compile this code and run it in terminal, I get
b
b
b
Therefore, I wonder exactly how to understand the execution process of #define and also other preprocessing commands.
Thanks.
CodePudding user response:
The file is scanned once and the c preprocessor (CPP) has a state it maintains through lines. At any line, the order in which the currently existing macros were defined does not matter:
#define A B // CPP notes down A->B
#define C A // CPP notes down C->A
A // Expands to B
B // Stays B
C // Expands to A, which again expands to B
#undef A // CPP removes the entry for A
#define A D // CPP notes down A->D
A // Expands to D
B // Stays B
C // Expands to A, which again expands to D
CodePudding user response:
The preprocessor does execute in order. Specifically, it executes line-by-line. Some of the lines are preprocessor directives (such as #define
); others are not. When the preprocessor processes a #define
directive, it does so by adding that definition to its set of macro definitions. When the preprocessor processes a regular line of code, it does so by (among other things) looking for tokens which match macro definitions and substituting them with the replacement. If the replacement itself includes macro names, those macros are again replaced.
So when it encounters c();
, it first uses the macro definition of c
to produce a();
. Then it uses the macro definition of a
to produce b();
. That contains no macro names to substitute, so it's done.
Note that the order of #define
statements relative to each other is unimportant. #define
simply puts entries in the macro table. They have no effect until they're used in regular lines of code.