转自 http://www.cnblogs.com/9sheng/archive/2011/03/22/2684247.html
一个令人比较迷惑的问题,学C语言好多年,今天终于搞明白,记之。
1 #define cat(x,y) x ## y 2 #define xcat(x,y) cat(x,y) 3 cat(cat(1,2),3) //为什么不是 123? 4 xcat(xcat(1,2),3) //结果为什么是 123?
要解答这个问题,首先看一下预处理过程的几个步骤:
- 字符集转换(如三联字符)
- 断行连接 /
- 注释处理, /* comment */,被替换成空格
- 执行预处理命令,如 #include、#define、#pragma、#error等
- 转义字符替换
- 相邻字符串拼接
- 将预处理记号替换为词法记号
在这里主要关注第4步,即如何展开函数宏。(其他步骤和本文关系不大,但对于理解预处理过程是十分重要的)宏函数替换展开,规则可简单总结如下:在展开当前宏函数时,如果形参有#(字符串化操作)或##(记号连接操作)则不进行宏参数的展开,否则先展开宏参数,再展开当前宏(就像先计算函数中的参数,然后调用函数一样)。回头看最初的问题,则两个宏展开过程如下:
cat(cat(1,2),3)
=> cat(1,2) ## 3 // cat(x,y) x##y参数前有##操作,参数不展开
=> cat(1,2)3 // K&R中说,)3 是一个不合法记号,不展开
xcat(xcat(1,2),3)
=> xcat(cat(1,2),3) //xcat(x,y) cat(x,y)参数前无#,##操作,则先展开参数
=> xcat(1 ## 2,3)
=> xcat(12,3)
=> cat(12,3)
=> 12 ## 3
=> 123
有兴趣的话,可以看下面一些宏替换问题:
1 #define X 3 2 #define Y X*2 3 #undef X 4 #define X 2 5 int z=Y; // z = 4 6 7 #define hash_hash # ## # 8 #define mkstr(a) # a 9 #define in_between(a) mkstr(a) 10 #define join(c, d) in_between(c hash_hash d) 11 char p[] = join(x, y); // 等同于char p[] = "x ## y"; 12 13 #define connect(x) i ## x 14 #define connect2(x) connect(x) 15 #define s(a) a 16 #define is(a) a 17 int i2=2; 18 printf("%d/n", connect(s(1)));/*connect的形参x是##的操作数,故不展开它对应的实参s,直接连接记号i和实参序列s(1),得到is(1),继续替换得到最后结果1*/ 19 printf("%d/n", connect2(s(2)));/*connect2的形参x不是##的操作数,故先展开它对应的实参s,再用展开结果2替换之,得到connect(2),继续替换得到最后结果i2*/ 20 21 #define TEST(a,b) / 22 do {/ 23 printf(#a "=%d/n", a); / 24 printf(#b "=%d/n", b); / 25 } while (0) 26 // 为什么要写在 do {} while (0) 中呢?而不是{}
本文参考资料,强烈推荐一看:
http://blog.youkuaiyun.com/huyansoft/archive/2008/05/26/2484297.aspx
http://www.mikeash.com/pyblog/friday-qa-2010-12-31-c-macro-tips-and-tricks.html