ProtocolKit中宏的用法分析

宏本身不难理解,但是往往嵌套多了,或者利用一些不常用的特性之后,会让人觉得迷惑.

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);

可是根据编译器的警告来看,并不是我想要的结果:

20160926147485714436151.jpg

原来在##的作用下,__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__);
2016092614748581939059.jpg

发现结果正确.

我这种写法,需要使用者传递多个参数,也已经必须嵌套一层了.作者在此基础上加上默认的参数实现,也是很合理的.

另外可以看到,这个$符号,不加也可以,所以,个人猜想.这个和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的文档中,也有关于可变参数宏的说明.在此,就不赘述了,想深入了解的,可以查看文档

你可能感兴趣的:(ProtocolKit中宏的用法分析)