【转】一个C语言宏展开问题

来源:互联网 发布:windows 清空dns缓存 编辑:程序博客网 时间:2024/06/16 14:28

转自   http://www.cnblogs.com/9sheng/archive/2011/03/22/2684247.html

一个令人比较迷惑的问题,学C语言好多年,今天终于搞明白,记之。

1 #define cat(x,y)  x ## y2 #define xcat(x,y) cat(x,y)3 cat(cat(1,2),3) //为什么不是 123?4 xcat(xcat(1,2),3) //结果为什么是 123?

要解答这个问题,首先看一下预处理过程的几个步骤:

  1. 字符集转换(如三联字符)
  2. 断行连接 /
  3. 注释处理, /* comment */,被替换成空格
  4. 执行预处理命令,如 #include、#define、#pragma、#error等
  5. 转义字符替换
  6. 相邻字符串拼接
  7. 将预处理记号替换为词法记号

在这里主要关注第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 ## x14 #define connect2(x) connect(x)15 #define s(a) a16 #define is(a) a17 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.csdn.net/huyansoft/archive/2008/05/26/2484297.aspx
http://www.mikeash.com/pyblog/friday-qa-2010-12-31-c-macro-tips-and-tricks.html

0 0
原创粉丝点击