您的位置:首页 > 其它

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的扩展也会在后篇继续学习了解。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: