宏参数(Arguments)的扩展
宏分为两种,一种是 object-like 宏,比如:
#define STR "Hello, World!"
另一种是 function-like 宏,比如:
#define MIN(X, Y) ((X) < (Y) ? (X) : (Y))
对于 function-like 宏,定义时的参数叫 Parameters,比如上面宏 MIN 的参数 X、Y,当调用时,传递的参数叫 Arguments。
宏参数 Arguments
当给宏传递参数 Arguments 时,可以不用全部传递,比如:
MIN(a, b) -> ((a) < (b) ? (a) : (b)) // 完全传递 MIN(, b) -> (() < (b) ? () : (b)) // 只传递后一个 MIN(a, ) -> ((a) < () ? (a) : ()) // 只传递前一个 MIN(,) -> (() < () ? () :()) // 这种允许 MIN(, ,) // 报错,接收2个参数,传递了3个 MIN() // 报错,接收2个参数,传递了1个
宏参数 Arguments 的扩展
当向宏中传递参数 Arguments 时,在参数替换到宏里面之前,首先要对参数 Arguments 进行完全的扩展,当参数扩展完毕之后,才将最终扩展的结果替换到宏里面,同时再对整个宏进行扩展。比如调用宏 MIN(MIN(a, b), c),那么首先第一个参数 MIN(a, b)要进行扩展,扩展的结果为 ((a) < (b) ? (a) : (b)),由于第2个参数 c 不用扩展,也就是第1步得到的扩展结果为:
MIN(((a) < (b) ? (a) : (b)), c)
接下来进行第2步扩展,得到的结果为:
((((a) < (b) ? (a) : (b))) < (c) ? (((a) < (b) ? (a) : (b))) : (c))
这样做的一个好处是为了防止宏的嵌套调用,比如有下面一个宏定义:
#define f(x) x
如果有如下调用 f(f(1)),假设第一步不将参数 f(1) 完全展开,就会出现 f(f(1)) 被展开为 f(1),由于间接的自引用,宏不再继续展开,此时得到的结果就为 f(1)。而有了2步扩展,第一步参数 f(1) 被扩展成 1,然后替换后继续扩展,可以得到结果就是1。
自引用宏
一个宏在定义时,如果宏名出现在了宏定义中,那么就是一个自引用宏,比如:
#define foo (4 + foo)
如果调用这个宏 foo,按照上面两步展开的过程,那么将会是一个无限循环的过程。首先 foo 展开为 (4 + foo),然后 (4 + foo) 中的 foo 继续展开成 (4 + foo) 成为 (4 + (4 + foo)),如此继续下去。但是实际上,对于自引用宏,只扩展1次,后面不会再做扩展,也就是说调用宏 foo,最终的扩展结果就是 (4 + foo)。
对于自引用宏的一种特殊情况就是间接自引用,比如有如下宏定义:
#define x (4 + y)
#define y (2 * x)
当调用宏 x 时,首先扩展为 (4 + y),然后对 y 进行扩展,结果为 (4 + (2 * x)),如果此时继续对 x 进行扩展,那么就会无限递归,为了处理这种情况,扩展会在这一步终止,也就是最终结果是 (4 + (2 * x))。
当调用宏 y 时一样,首先扩展为 (2 * x),然后对 x 进行扩展,结果为 (2 * (4 + y)),扩展到这一步也会停止。
参数 Arguments 有字符串化(#)和连接(##)操作
在宏扩展过程当中,当参数 Arguments 有字符串化(#)和连接操作(##)时,参数的扩展就没有第1步。比如有下面宏定义:
#define AFTERX(x) X_ ## x
#define XAFTERX(x) AFTERX(x)
#define TABLESIZE 1024
#define BUFSIZE TABLESIZE
当调用 AFTERX(BUFSIZE) 时,由于参数 BUFSIZE 有连接操作(##),那么它就不会继续扩展成 TABLESIZE,TABLESIZE 继续扩展成1024,而是直接使用,也就是最终的扩展结果是 X_BUFSIZE,而不是 X_10。如果想要得到 X_10 的结果,需要做1次间接宏调用,重新定一个宏 XAFTERX 来调用宏 AFTERX,当调用宏 XAFTERX(BUFSIZE) 时,就会得到结果 X_10。
宏参数(Arguments)的扩展的更多相关文章
- js参数arguments的理解
原文地址:js参数arguments的理解 对于函数的参数而言,如下例子 function say(name, msg){ alert(name + 'say' + msg); } say('xiao ...
- C/C++语言中#的神奇作用:把宏参数字符串化/贴合宏参数
宏中"#"和"##"的用法 一.一般用法 我们使用#把宏参数变为一个字符串,用##把两个宏参数贴合在一起. #define STR(s) #s # ...
- C/C++中 # 的神奇作用:把宏参数字符串化/贴合宏参数
一.一般用法 我们使用#把宏参数变为一个字符串,用##把两个宏参数贴合在一起. #define STR(s) #s #define CONS(a,b) int(a##e##b) printf(ST ...
- [译]Javascript 参数(arguments)对象
本文翻译youtube上的up主kudvenkat的javascript tutorial播放单 源地址在此: https://www.youtube.com/watch?v=PMsVM7rjupU& ...
- 函数的默认值与动态参数arguments的总结
在js函数与作用域,了解函数基本概念中,我们发现当函数的实参有一个没有上传的时候,对应的形参time展示的值就是undefined,如下代码所示: <!DOCTYPE html> < ...
- C语言:宏参数的字符串化和宏参数的连接
在宏定义中,有时还会用到#和##两个符号,它们能够对宏参数进行操作. # 的用法 #用来将宏参数转换为字符串,也就是在宏参数的开头和末尾添加引号.例如有如下宏定义: #define STR(s) #s ...
- 隐式参数arguments
类数组对象中(长得像一个数组,本质上是一个对象):arguments 常见的对arguments的操作是三个 获取参数的长度 arguments.length 根据索引值获取某一个参数 argume ...
- Confluence 6.15 博客页面(Blog Posts)宏参数
参数是让你可以用来控制宏的格式和输出的选项.在 Confluence 存储格式或者 Wiki 标记(wikimarkup)中使用的参数名与在宏浏览器中使用的标签名是不同的,在下面我们将会用括号列出 ...
- js的隐含参数(arguments,callee,caller)使用方法
在提到上述的概念之前,首先想说说javascript中函数的隐含参数: arguments arguments 该对象代表正在执行的函数和调用它的函数的参数.[function.]arguments[ ...
随机推荐
- 安装 mysql 8.0后;root用户在客户端连接不上
--- mysql workbench Failed to Connect to MySQL at 10.211.55.6:3306 with user root Authentication plu ...
- 微服务技术栈简单介绍,Eureka和Ribbon的引入和使用
一.了解微服务架构 1.微服务技术栈 整体框架 整体学习规划路线2.微服务与单体架构的区别 单体架构:将业务的所有功能集中在一个项目中开发,打成一个包部署 优势 结构简单 部署成本低 缺点 耦合度高, ...
- Linux忘记Root密码怎么找回
进入1级别,单用户模式 ,修改root密码即可(运行级别不懂看这里) 具体操作如下: 1.开机时按enter键 2.进入GRUB界面 3.输入 e,在引导系统前编辑命令 4.选择第二行 kernel ...
- Linux系统安装(CentOS-7)详细操作步骤
Linux系统安装(CentOS-7)详细操作步骤 一.创建虚拟机 首先创建一个虚拟机,然后才能在虚拟机里面安装系统. 第一步,创建虚拟机的向导 第二步,兼容性默认即可. 第三步,我们等创建完虚拟机后 ...
- 扯 C++ 里的 Lambda
之前写(抄) parsec 的时候, 在重载 operator>> 的时候, operator>> 需要接收一个 lambda, 之后返回一个 Component<R&g ...
- Note/Solution -「洛谷 P6466」分散层叠算法
\(\mathcal{Description}\) Link. 给定 \(m\) 个长度为 \(n\) 的有严格升序且不包含重复元素的序列 \(a_1,a_2,\cdots,a_m\),\(q ...
- suse 12 二进制部署 Kubernetets 1.19.7 - 第11章 - 部署coredns组件
文章目录 1.11.0.部署coredns 1.11.1.测试coredns功能 suse 12 二进制部署 Kubernetes 集群系列合集: suse 12 二进制部署 Kubernetets ...
- Node.JS学习——学习笔记
Node.JS--学习笔记 2020年02月23日11:52:01 我打算自学NodeJS-通过阅读NodeJS官网来完成. https://nodejs.org/dist/latest-v13.x/ ...
- 『德不孤』Pytest框架 — 6、Mark分组执行测试用例
目录 1.Pytest中的Mark介绍 2.Mark的使用 3.Mark的注册和使用 4.使用Mark完成失败重试 5.扩展 1.Pytest中的Mark介绍 Mark主要用于在测试用例/测试类中给用 ...
- unittest测试框架,HTMLTestReportCN模块生成的测试报告中展示用例说明的配置方法
1.前言 想要生成的html测试报告中展示每个测试用例的说明信息,方便了解测试案例的测试点或者其他信息,目前知道的有2种 2.方法介绍 * 方法1: 要添加说明的测试用例,将说明信息用3个引号包裹起来 ...