博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
C宏展开的几个注意事项
阅读量:5346 次
发布时间:2019-06-15

本文共 2428 字,大约阅读时间需要 8 分钟。

前阵子仔细重新研究了一下C的宏展开。总结起来,有以下几个主要规则:

  1. 每次宏展开的结果会被重复扫描,直到没有任何可展开的宏为止。
  2. 每展开一个宏,都会记住这次展开,在这个宏展开的结果及其后续展开中,不再对相同的宏做展开。
  3. 带参数的宏,先对参数做展开,除非宏定义体中包含#或##
    a) #表示将后续标识符转换为字符串
    b) ##表示将两个标识符连接成一个标识符
    c) 注意参数展开的结果中即使有逗号(,),也不视为参数的分隔符
  4. 如果宏定义中带有参数,而代码中出现同样标识符时没有参数,不视为宏。

下面的三段代码分别解释了2, 3, 4. 注释中描述了宏每一步展开的细节

这段代码主要解释规则2.(~表示已经被展开过)

#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)

这段代码主要解释规则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

这段代码主要解释规则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)

转载于:https://www.cnblogs.com/aquastone/p/c-macro-expansion.html

你可能感兴趣的文章
session和xsrf
查看>>
Linux目录结构
查看>>
luoguP3414 SAC#1 - 组合数
查看>>
五一 DAY 4
查看>>
(转)接口测试用例设计(详细干货)
查看>>
【译】SSH隧道:本地和远程端口转发
查看>>
图片点击轮播(三)-----2017-04-05
查看>>
直播技术细节3
查看>>
《分布式服务架构:原理、设计于实战》总结
查看>>
java中new一个对象和对象=null有什么区别
查看>>
字母和数字键的键码值(keyCode)
查看>>
IE8调用window.open导出EXCEL文件题目
查看>>
Spring mvc初学
查看>>
有意思的代码片段
查看>>
C8051开发环境
查看>>
VTKMY 3.3 VS 2010 Configuration 配置
查看>>
01_1_准备ibatis环境
查看>>
windows中修改catalina.sh上传到linux执行报错This file is needed to run this program解决
查看>>
JavaScript中的BOM和DOM
查看>>
360浏览器兼容模式 不能$.post (不是a 连接 onclick的问题!!)
查看>>