宏本身不难理解,但是往往嵌套多了,或者利用一些不常用的特性之后,会让人觉得迷惑.
ProtocolKit中的一段宏定义
在ProtocolKit
中有这么一段宏的定义:
// Get container class name by counter
#define _pk_get_container_class($protocol) _pk_get_container_class_imp($protocol, __COUNTER__)
#define _pk_get_container_class_imp($protocol, $counter) _pk_get_container_class_imp_concat(__PKContainer_, $protocol, $counter)
#define _pk_get_container_class_imp_concat($a, $b, $c) $a ## $b ## _ ## $c
当时知道:
##
连字符,通常用来拼接
__COUNTER__
计数器,一般用来后缀在变量上面,保证变量的唯一性.在程序中,每使用一次,这个数字就+1
,默认是0
再看实际拼接的结果:
_pk_get_container_class(MyProtocol);
//相当于
__PKContainer_MyProtocol_0;
一开始的时候在想, 不就是要拼接么,为何要弄那么多层嵌套.难道是故意增加复杂度,让人觉得高深? 还有变量前面的$
,是和shell中的一个意思? 表示变量?
尝试简化
遇到看不懂的东西,我喜欢先去掉,把自己知道的代码罗列出来.然后依次加上不懂得东西,看它对既有结果的改变.然后判断它的作用.
于是,我写了下面一个宏:
#define _kn_get_container_class(prefix,protocol) prefix##_##protocol##_##__COUNTER__
然后使用:
NSString * _kn_get_container_class(__kn,MyProtocol);
可是根据编译器的警告来看,并不是我想要的结果:
原来在##
的作用下,__COUNTER__
被当成了字面上的表示,并没有解析.
然后,根据作者的写法,把实现加深一层,改写为:
#define _simpleifyGetContainerClass(prefix,protocol,counter) _simple_getContainerClass_imp(prefix,protocol,counter)
#define _simple_getContainerClass_imp(a,b,c) a##b##_##c
调用
NSString * _simpleifyGetContainerClass(__PKContainer_,MyProtocol,__COUNTER__);
发现结果正确.
我这种写法,需要使用者传递多个参数,也已经必须嵌套一层了.作者在此基础上加上默认的参数实现,也是很合理的.
另外可以看到,这个$
符号,不加也可以,所以,个人猜想.这个和shell中使用变量
不是一回事.可能加上仅仅为了阅读者明白,这个地方是个变量.若理解不正确,请您指正.
GCC中一个可变参数的宏
之前项目中,封装过打印.当时就用到了可变参数的宏:
#define GUIError(message,...) DDLogError(@"\n[ FILE ] %s \n[ METHOD ] %s\n[ LINE ] %d \n[ Message ]\n%@\n\n=======================================================\n",__FILE__,__FUNCTION__,__LINE__,[NSString stringWithFormat:message,## __VA_ARGS__])
就是在定义的时候,以...
作为最后一个参数,使用的时候,__VA_ARGS__
就代指这一系列可变参数.
今天想找找关于宏的资料,发现GCC的文档中,也有关于可变参数宏的说明.在此,就不赘述了,想深入了解的,可以查看文档