Clang 宏定义初探(二)
来源:互联网 发布:渠道营销 知乎 编辑:程序博客网 时间:2024/05/16 13:03
Clang 宏定义初探(二)
本篇总结下这几天看的宏的一些看到的用法。
1、参数粘结
这是一个类似 shell 之类的脚本语言的特性,可以利用这个特性完成一些重复度比较高的编码的简化。
例如,对proc文件系统进行绑定的时候,需要在/proc/test/目录下,简历3个文件接口,test1、test2、test3.
可以这样写
#define BIND(x) test##x->read_proc=test##x##_read
在使用的时候,就可以
BIND(1); //展开为test1->read_proc=test1_read;BIND(2); //展开为test2->read_proc=test2_read;
不管是从语义还是编码复杂度,都降低了。
2、参数字符化
在使用单个 # 号,作为函数式宏的参数前缀时,可以让宏的内容变成字符串,比如说:
#define print(x) do{\printf(#x);\printf("=%d\n",x);\}while(0)
使用的时候,直接写:
int t = 1;print(t);
结果会是 t=1,这个在做日志的时候还是非常好用的。
3、do{…}while(0) 和 ({…})
可以认为是前者是 void 函数,后者是有 return 值的函数。
入2中所示,do{…}while(0) 是为了产生一个程序块,当宏里有多条需要语句需要执行时,如果不适用这种do{…}while(0)的形式,可能导致一些隐形的错误,例如:
#define print(x) {printf(#x);printf("=%d\n",x);
正常的:
print(t); 是没有问题的,但是如果放在程序段里:
if( flag ) print(t);else print(a);
展开之后,会发现为
if( flag ){printf("t");printf("=%d\n",t);};else...
这个语法就错了。因此,当代码段比较多,且不需要返回值时就用 do{…}while(0) 吧。
另外一种方式属于 GNU 的扩展,后续在看。
4、多重展开
还是基于打印的例子,我需要打印一些列举的参数值:
#define P(x) arg##x#define print(x) do{printf(#P(x));printf("=%d\n",P(x));}while(0)
这个编译通不过,换成以下方式即可:
#define P(x) arg##x#define __print(x) do{printf(#x);printf("=%d\n",x);}while(0)#define _print(x) __print(x)#define print(x) _print(P(x))
修改成这样,解决了想要的解决的问题:
int arg1 = 1;print(1);
输出结果为:arg1=1
主要涉及的问题在于宏的多次展开,宏每次展开只会对当前的输入参数进行一次展开,当你的输入值也是个宏的时候,就需要使用过度宏,让你的输入接着展开。
对于多次展开没有从最根本的原理解释,只是从实验感官上对这个特性做了分析,实际上,自己也不会写出那么复杂的宏(怕中间调用出漏洞)。
宏的基本常见用法,都差不多枚举了一番,往后在见到更高级的玩法和比较精髓的写法往后再慢慢补充上来吧,另外GNU的扩展也会在后篇继续学习了解。
- Clang 宏定义初探(二)
- Clang 宏定义初探(一)
- clang static analyzer源码分析(二)
- Hibernate初探(二)
- COM初探(二)
- tolua++初探(二)
- GDB初探(二)
- quartz初探(二)
- Hadoop初探(二)
- Scala初探(二)
- Oracle初探(二)
- OpenMANO初探(二)
- 初探UiAutomator(二)
- 异常初探(二)
- 多线程初探(二)
- 集合初探(二)
- opencv初探(二)
- TrustZone初探 (二)
- Java堆、栈、方法区、常量池
- 判断当前应用程序处于前台还是后台 ANDROID
- [并查集] hdu1272 小希的迷宫
- ELM的算法及伪代码
- 搭建linux服务器之Vim配置
- Clang 宏定义初探(二)
- POJ-1422-Air Raid-求最小路径覆盖(匈牙利算法)
- 我为什么从Angular转向React?
- 全排列
- kernel 中的红黑树
- 阶段计划
- 设计模式
- 二分图小结
- 设置UITextField的placeholder的颜色及字体