Clang 宏定义初探(二)
2016-03-11 01:39
225 查看
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的扩展也会在后篇继续学习了解。
相关文章推荐
- C/C++ 宏详细解析
- 深入探讨:宏、内联函数与普通函数的区别
- C++十六进制宏的用法详解
- C++基础入门教程(二):数据、变量、宏等
- 枚举和宏的区别详细解析
- 浅析c++ 宏 #val 在unicode下的使用
- 如何在C语言的宏中使用类型关键字
- c/c++ 宏定义中的#/##
- 树形结构
- 巧用可变参数宏、编译器内置宏和printf输出调试信息
- 用宏获取函数名
- C语言之“宏”
- do...while(0)在宏定义中的巧妙用法
- do...while(0)在宏定义中的巧妙用法
- 万能类型的设计
- 单例的宏模板
- office(excel/word/ppt)宏工程,vba工程密码去除
- C/C++预处理器总结
- 黑马程序员---【C语言】06预处理命令
- typedef和define区别