1. 前言
写编译型语言多多少少都会遇到宏的使用,尤其是写oc,将一些事情放在预处理阶段做的话还是有很多好处的。
例如:
- 不扩大二进制体积
- 不占用运行时
- 代码简洁
- 深入理解预处理过程
很多优秀的框架都采用大量宏来维持简介的代码结构,治理友情链接同学对rac这个框架的宏的分析高手同学的友情链接
2. “#”和”##”的存在意义
“#”和”##”这两个宏用来把宏的参数变成字符串或者和其他字符相连,试想没有这两个宏语法是否可以实现相同功能,或者一个可以实现另一个。
为了消除二义性,如果不用#
而是用"A"
的形式来生成字符串的话,
1
| #define stringfiy(A) "A"
|
stringfiy(a) 的结果到底是 “a” 还是 “A” 是不明确的
同样
1
| #define CONCATG(A, B) AB
|
CONCATG(a, b) 的结果到底是 ab 还是 AB 是不明确的
无法通过 #
来实现 ##
1 2 3
| #define MY_CONTACT(A, B) #A#B MY_CONTACT(a, b) //"1""1" MY_CONTACT(a, b) //"a""b"
|
生成的是字符串,而不是宏的名字,无法进一步做宏替换。
无法通过 ##
来实现 #
1
| #define stringfiy(A) "##A##"
|
stringfiy(a) 只会得到字符串"##A##"
3. 中间宏的使用
在课上例子里用到了_CONCAT
宏,这个宏其实和直接使用##
语法基本等效,但是直接使用##
会有一些问题。直接使用_CONCAT
因为展开后马上要执行##
,所以类似 _CONCAT(1, _CONCAT(2, 3))
这样的嵌套操作是无法进行的,第一次展开会得到1_CONCAT(2, 3)
这样的结果,发生错误,如果再定义一层 CONCAT
1
| #define CONCAT(A, B) _CONCAT(A, B))
|
CONCAT(1, CONCAT(2, 3))
展开后不会马上进行 ##,所以可以顺利得到123
1 2 3 4 5 6 7
| CONCAT(1, CONCAT(2, 3)) _CONCAT(1, CONCAT(2, 3)) _CONCAT(1, _CONCAT(2, 3)) _CONCAT(1, 2 ## 3)) _CONCAT(1, 23)) 1 ## 23 123
|
4. 宏的举例使用
5. 例子的改进
尝试让IS_EQ宏支持大的数在前面。
通过把-1换成SUB1,让宏可以正常识别来解决,缺点是 DEC 和 ARG_AT 会失去通用性。
1 2 3 4 5 6
| #define _ARG_ATSUB1(_0, ...) SUB1 #define _IS_EQ0_SUB1 0
//修改 DEC #define DEC(N) \ ARG_AT(N, SUB1, 0, 1, 2, 3, 4)
|
完整的宏定义如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| #define ARG_AT(INDEX, ...) _ARG_AT##INDEX(__VA_ARGS__)
#define _ARG_ATSUB1(_0, ...) SUB1 #define _ARG_AT0(_0, ...) _0 #define _ARG_AT1(_0, _1, ...) _1 #define _ARG_AT2(_0, _1, _2, ...) _2 #define _ARG_AT3(_0, _1, _2, _3, ...) _3 #define _ARG_AT4(_0, _1, _2, _3, _4, ...) _4 #define _ARG_AT5(_0, _1, _2, _3, _4, _5, ...) _5
#define DEC(N) \ ARG_AT(N, SUB1, 0, 1, 2, 3, 4)
#define IS_EQ(A, B) _CONCAT(_IS_EQ, A)(B)
#define _CONCAT(A, B) A ## B
#define _IS_EQ0(B) _CONCAT(_IS_EQ0_, B)
#define _IS_EQ0_SUB1 0 #define _IS_EQ0_0 1 #define _IS_EQ0_1 0 #define _IS_EQ0_2 0 #define _IS_EQ0_3 0 #define _IS_EQ0_4 0 #define _IS_EQ0_5 0
#define _IS_EQ1(B) _IS_EQ0(DEC(B)) #define _IS_EQ2(B) _IS_EQ1(DEC(B)) #define _IS_EQ3(B) _IS_EQ2(DEC(B)) #define _IS_EQ4(B) _IS_EQ3(DEC(B)) #define _IS_EQ5(B) _IS_EQ4(DEC(B))
|
6. 创建IS_GT(A, B)宏
现在尝试创建一个IS_GT(A, B)
宏,当 A 比 B 大的时候为1, 否则为0。
和IS_EQ
相比只要稍微修改一下 IS_GT0_N 最后映射的值就实现了 IS_GT
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| #define IS_GT(A, B) _CONCAT(_IS_GT, A)(B)
#define _IS_GT0(B) _CONCAT(_IS_GT0_, B)
#define _IS_GT0_SUB1 1 #define _IS_GT0_0 0 #define _IS_GT0_1 0 #define _IS_GT0_2 0 #define _IS_GT0_3 0 #define _IS_GT0_4 0 #define _IS_GT0_5 0
#define _IS_GT1(B) _IS_GT0(DEC(B)) #define _IS_GT2(B) _IS_GT1(DEC(B)) #define _IS_GT3(B) _IS_GT2(DEC(B)) #define _IS_GT4(B) _IS_GT3(DEC(B)) #define _IS_GT5(B) _IS_GT4(DEC(B))
|