文章正文
STR( CON_STR(1, 2))比较好理解,当碰到包含#或者##的宏定义,参数则不再展开,所以展开的结果为"CON_STR(1, 2)"。
对于CALL_STR( CON_STR(1, 2))这个来说,如果按照顺序直观的展开应该是CALL_STR( CON_STR(1, 2)) -> STR(CON_STR(1, 2)) -> "CON_STR(1, 2)"
CALL_STR( CON_STR(1, 2)) -> STR(CON_STR(1, 2)) -> STR(12)
STR(12) -> "12"
第一轮 平行展开:f/s/f/cat/h/cat
第二轮 平行展开: h/g
第三轮 平行展开: g
C语言宏定义展开方式
测试环境
Mac OS(Big Sur) + Apple clang version 12.0.5
我们先说结论:**宏定义由外向内平行展开,当碰到##或着#宏,参数不再做宏展开**
下面用例子说明
示例
#define CON_STR(a, b) a ## b #define STR(a) #a #define CALL_STR(arg) STR(arg) // CON_STR( CON_STR(1, 2), 3 ); // CON_STR( STR(1), 3 ); // CON_STR( CALL_STR(1), 3 ); // CALL_STR( CON_STR( STR(1), 2) ); CON_STR( 3, CALL_STR(1) ); CON_STR( 3, STR(2) ); STR( CON_STR( 3, CALL_STR(2) ) ); STR( CON_STR(1, 2) ); CALL_STR( CON_STR(1, 2) ); CALL_STR( CON_STR(1, STR(2)) ); STR( CON_STR( 1, CALL_STR( CON_STR( 1, 2))) ); CALL_STR(CON_STR( 1, CALL_STR( CON_STR( 1, 2))) );
输出结果
使用命令做预处理$ clang -E define.c
注释的代码,如果运行,则预处理会出现错误,属于错误使用宏的方法。
上面的示例输出如下:
3CALL_STR(1); 3STR(2); "CON_STR( 3, CALL_STR(2) )"; "CON_STR(1, 2)"; "12"; "1STR(2)"; "CON_STR( 1, CALL_STR( CON_STR( 1, 2)))"; "1CALL_STR( CON_STR( 1, 2))";
分析
上面的结论说宏定义会由外向内平行展开,这里的平行展开怎么理解呢?
这里主要看STR( CON_STR(1, 2)) 和 CALL_STR( CON_STR(1, 2))这两个函数
但是由于CALL_STR不包含#和##,所以需要平行展开。这个例子可以分成两步:第一步将所有的都展开一次,第二步将第一步的结果再张开一次。
思考
#define f(a, b) a fff b #define g(a) #a #define h(a) g(a) #define s(a) h(a) #define cat(a, b) a ## b f(s(f(cat(1, 2),3)), h(cat(4, 5)))
解析:
f(s(f(car(1, 2),3)), h(cat(4, 5))) ->
s(f(car(1, 2),3)) fff h(cat(4, 5)) ->
h(f(car(1, 2),3)) fff h(cat(4, 5)) ->
h(car(1, 2) fff 3) fff h(cat(4, 5)) ->
h(12 fff 3) fff h(cat(4,5)) ->
h(12 fff 3) fff g(cat(4,5)) ->
h(12 fff 3) fff g(45)
h(12 fff 3) fff g(45) ->
g(12 fff 3) fff g(45) ->
g(12 fff 3) fff "45"
g(12 fff 3) fff "45" ->
"12 fff 3" fff "45"
所以结果就是"12 fff 3" fff "45"
如有错误欢迎评论指正
Jan. 1, 2022, 4:32 p.m. 作者:zachary 分类:C语言 阅读(2403) 评论(0)