转自一个C语言宏展开问题

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

-------------------------------------------------------------

#define cat(x,y)  x ## y

#define xcat(x,y) cat(x,y)

cat(cat(1,2),3) //为什么不是 123?

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

-------------------------------------------------------------

有兴趣的话,可以看下面一些宏替换问题:

-------------------------------------------------------------

#define X 3

#define Y X*2

#undef  X

#define X 2

int z=Y; // z = 4

-------------------------------------------------------------

#define hash_hash # ## #

#define mkstr(a) # a

#define in_between(a) mkstr(a)

#define join(c, d) in_between(c hash_hash d)

char p[] = join(x, y); // 等同于char p[] = "x ## y";

-------------------------------------------------------------

#define connect(x) i ## x

#define connect2(x) connect(x)

#define s(a) a

#define is(a) a

int i2=2;

printf("%d/n", connect(s(1)) );/*connect的形参x是##的操作数,故不展开它对应的实参s,直接连接记号i和实参序列s(1),得到is(1),继续替换得到最后结果1*/

printf("%d/n", connect2(s(2)) );/*connect2的形参x不是##的操作数,故先展开它对应的实参s,再用展开结果2替换之,得到connect(2),继续替换得到最后结果i2*/

-------------------------------------------------------------

#define TEST(a,b) /

do {/

printf(#a "=%d/n", a); /

printf(#b "=%d/n", b); /

} while (0)

一个C语言宏展开问题的更多相关文章

  1. c语言 预处理的使用 宏展开下的#,##

    1. #include   包含头文件 2.define 宏定义(可以理解为替换,不进行语法检查) 写法 #define 宏名 宏体  加括号 #define ABC (5+3) #define AB ...

  2. C宏展开的几个注意事项

    前阵子仔细重新研究了一下C的宏展开.总结起来,有以下几个主要规则: 每次宏展开的结果会被重复扫描,直到没有任何可展开的宏为止. 每展开一个宏,都会记住这次展开,在这个宏展开的结果及其后续展开中,不再对 ...

  3. 第一个C语言编译器是怎样编写的?

    首先向C语言之父Dennis MacAlistair Ritchie致敬! 当今几乎所有的实用的编译器/解释器(以下统称编译器)都是用C语言编写的,有一些语言比如Clojure,Jython等是基于J ...

  4. C中宏展开问题

    C中宏展开问题 简单记录一下碰到的问题. #define STR(x) #x 我们知道使用上面的宏可以将x转换为字符串"x". 但是如果这样用: #define NUM 3 #de ...

  5. 【做中学】第一个 Go 语言程序:漫画下载器

    原文地址: 第一个 Go 语言程序:漫画下载器: https://schaepher.github.io/2020/04/11/golang-first-comic-downloader 之前学了点 ...

  6. 你知道第一个C语言C++编译器是如何诞生的吗?

    当今几乎所有的实用的编译器/解释器(以下统称编译器)都是用 C 语言编写的,有一些语言比如 Clojure,Jython 等是基于 JVM 或者说是用 Java 实现的,IronPython 等是基于 ...

  7. 第一个C语言程序

    从第一个C语言程序了解C语言 了解关键字 了解函数 注释 C语言的执行流程 标识符 C语言的学习重难点 从第一个C语言程序了解C语言 上图是一个在控制台上显示“Hello, World!”的C语言源代 ...

  8. php调用一个c语言写的接口问题

    用php调用一个c语言写的soap接口时,遇到一个问题:不管提交的数据正确与否,都无法请求到接口 1.用php标准的soap接口去请求 2.拼接xml数据去请求 以上两种方式都不正确 解决办法:php ...

  9. 机器学习(一) 从一个R语言案例学线性回归

    写在前面的话 按照正常的顺序,本文应该先讲一些线性回归的基本概念,比如什么叫线性回归,线性回规的常用解法等.但既然本文名为<从一个R语言案例学会线性回归>,那就更重视如何使用R语言去解决线 ...

随机推荐

  1. CSS3选择器使用小结

    CSS3 选择器小结 一 通用选择器 1  *{}通配选择符(CSS2):适合所有元素对象. 2  E类型(HTML)选择符(CSS1):以文档语言对象类型DOM作为选择符. 3  E#myid是id ...

  2. Spark技术内幕:Stage划分及提交源码分析

    http://blog.csdn.net/anzhsoft/article/details/39859463 当触发一个RDD的action后,以count为例,调用关系如下: org.apache. ...

  3. ios错误修改了系统头文件

    一.打开终端 二.进入Xcode  输入命令: cd /Users/apple/Library/Developer/Xcode/ 三.打开当前 输入命令: open  . 四.将DerivedData ...

  4. 九度OJ 1442 A sequence of numbers

    题目地址:http://ac.jobdu.com/problem.php?pid=1442 题目描述: Xinlv wrote some sequences on the paper a long t ...

  5. OpenJudge 2786 Pell数列

    1.链接地址: http://bailian.openjudge.cn/practice/2786 2.题目: 总Time Limit: 3000ms Memory Limit: 65536kB De ...

  6. Ext 初级UI设计

    Ext.Button 说明:该组件代替了传统submit,reset,buuton HTML控件构造参数: text: 按钮上的名称 handler:指定一个函数句柄,在默认事件触发时调用,此时的默认 ...

  7. windows phone 网易云阅读hubtile效果实现

    效果图 曾几何时,刚接触wp的时候做了一个类似的界面,不过是Rectangle实现的,还是一个个摆的..囧啊 现在感觉这种应该是用hubtile实现的,Toolkit(http://silverlig ...

  8. form表单重置

    Jquery中重置表单的错误姿势 $('#yigeform').reset() 正确姿势 $('#yigeform')[0].reset()

  9. gdb提示Missing separate debuginfos, use: debuginfo-install glibc-2.12-1.132.el6_5.2.x86_64

    用gdb debugc代码的时候弹出这个错误 Missing separate debuginfos, use: debuginfo-install glibc-2.12-1.132.el6_5.2. ...

  10. jquery div拖动效果示例代码

    div拖动效果想必大家都有见到过吧,实现的方法也是有很多的,下面为大家将介绍使用jquery是如何实现的,感兴趣的朋友不要错过 复制代码代码如下: <%@ page language=" ...