The former array carefully re-examined the macro expansion of C. In summary, there are several main rules:
- The results of each macro expansion are scanned repeatedly until there are no expandable macros.
- Each time you expand a macro, you will remember this expansion, and in the result of the macro expansion and subsequent expansion, the same macro is no longer expanded.
- Macro with parameters, first expand the parameters, unless the macro definition body contains # or # #
A) #表示将后续标识符转换为字符串
b) # #表示将两个标识符连接成一个标识符
c) Note that even if there is a comma (,) in the result of the parameter expansion, it is not considered a delimiter for the parameter
- If there are parameters in the macro definition, and the same identifiers appear in the code, there are no parameters and are not considered macros.
The following three paragraphs explain 2, 3, 4, respectively. The details of each step of the macro are described in the comments
This code mainly explains Rule 2. (~ indicates that it has been expanded)
#define foo foo bar #define bar bar bar foo #define foo2(a) bar2(a,foo2) foo2(a) (a) #define bar2(a, b) foo2(a) bar2(a,b) (a) (b) foo // |-> foo bar // | |~ |-> bar bar foo // |-> foo bar bar foo (至此,所有符号都已展开过) bar // |-> bar bar foo // | |~ |~ |-> foo bar // |-> bar bar foo bar (至此,所有符号都已展开过) foo bar // foo bar // | | // |-> foo bar bar bar foo // | |~ | |~ |~ | // |-> foo bar bar foo bar bar foo bar foo2(1) // |-> bar2(1, foo2) foo2(1) (1) // | | |~ // |-> foo2(1) bar2(1, foo2) (1) (foo2) foo2(1) (1) bar2(1, 1) // |-> foo2(1) bar2(1,1) (1) (1) // | | |~ // |-> bar2(1,foo2) foo2(1) (1) bar2(1,1) (1) (1)
This code mainly explains rule 3.
#define foo vfoo #define bar vbar #define foo2(a) #a #define foo3(a, b) a ## _ ## b #define foo20(a) foo2(a) #define foo30(a, b) foo3(a, b) #define foo40(x) foo30(x) #define x x1,x2 foo2(foo) // -> "foo" (‘#‘阻止了参数展开,如果需要展开参数,定义另一个宏,见foo20) foo3(foo, bar) // -> foo_bar (‘##‘阻止了参数展开,如果需要展开参数,定义另一个宏,见foo30) foo20(foo) // | |-->vfoo (foo20带有一个参数,匹配宏定义,先展开参数) // | | // |-> foo2(vfoo) // |-> "vfoo" foo30(foo, bar) // | |-->vfoo, |->vbar // | | | // |-> foo3(vfoo, vbar) // |-> vfoo_vbar foo30(x) // 错误,参数个数不匹配, x中的逗号不视为参数分隔符。如果需要将这个逗号作为分隔符,定义另一个宏,见foo40 foo40(x) // | |-> x1,x2 // |-> foo30(x1,x2) //这个时候,逗号视为合法分隔符。 // |-> foo3(x1,x2) // |-> x1_x2
This code mainly explains rule 4.
#define foo(a) foo=a(x) #define bar(a) (bar=a) #define foo2(a) foo=a(x,y) #define bar2(a,b) bar(a*b) foo // 参数个数不匹配,不认为是宏 bar // 同上 foo(bar) // |-> foo=bar(x) (bar无参数,不认为是宏) // |-> foo=(bar=x) (此次扫描,bar符合宏定义) foo2(bar2) // |-> foo=bar2(x,y) (bar2无参数,不认为是宏) // |-> foo=bar(x*y) (此次扫描,bar符合宏定义) // |-> foo=(bar=x*y)
Several considerations for C-Macro expansion