参考文章:https://onevcat.com/2014/01/black-magic-in-macro/
http://www.cnblogs.com/alexshi/archive/2012/03/09/2388453.html
https://zhidao.baidu.com/question/425382312987430932.html
宏分为两类
-
对象宏(object-like macro)
-
函数宏(function-like macro)
对象宏
对象宏相对比较简单,一般是用来定义一些常数:
#define M_PI 3.14159265358979323846264338
编译时,编译器会在语义分析认定是宏,会将 M_PI 替换为具体的圆周率数字,这个过程称为宏的展开。
函数宏
函数宏,意味着它的行为类似于函数;它可以接受参数。只要在宏名称(上面例子中的 M_PI 就是宏名称)的后面加上括号,就成为函数宏。
#define MIN(A, B) (A < B ? A : B)
这是一个比较两个数大小的宏,A和B 是宏可以接受的两个参数,宏展开时,它们会分别代入宏体中的 A和B。宏体用括号括起来是要防止宏展开时不如预期,例如
我要输出两个数字中较小数字的10倍:
#define MIN(A, B) A < B ? A : B
int a = 100;
int b = 200;
NSLog(@"smaller: %d", 10*MIN(a, b));
输出则为 200,跟预期的1000不一样。因为宏展开后是这样的
10 * a < b ? a : b
先做了乘法,再进行比较。所以不管是对象宏还是函数宏,这点都要注意。
关于#和##、__VA_ARGS__
# 运算符可以将宏的参数转化为字符串字面量,它仅仅出现在函数宏中。
使用方法
#define LOG(A, B) NSLog(@""#A" = %d, "#B" = %d" , A, B)
int main(int argc, char *argv[]) {
@autoreleasepool {
int a = 100;
int b = 200;
LOG(a, b);
}
}
输出为: a = 100, b = 200
## 运算符可以将两个标识符粘合在一起。如
#define GLUE(A, B) A##B
int main(int argc, char *argv[]) {
@autoreleasepool {
int a = 100;
int b = 200;
int ab = 300;
NSLog(@"%d", GLUE(a, b));
}
}
输出:300
__VA_ARGS__
在一些宏参数中会出现 ‘...’,‘...’ 指的是可变参数,意思是可以接受零个或者是多个参数。而在宏体里,对应的便是 __VA_ARGS__ ,例
#define WHLOG(fmt, ...) NSLog(fmt,__VA_ARGS__)
int main(int argc, char *argv[]) {
@autoreleasepool {
int a = 100;
WHLOG(@"Hello world %d", a);
}
}
输出为:Hello world 100
但是这里有个问题:当对 ‘...’ 输入零个参数的时候,当展开宏的时候会多了一个逗号出来,这时候编译会不通过。针对这个问题,可以用 ##__VA_ARGS__ 这个代替 __VA_ARGS__ ;当输入零个参数的时候,预处理器会把多出它之前多出的那个逗号去掉。
网友评论