对宏的简单认识和使用

2017-07-10  本文已影响9人  永远保持一颗进取心

参考文章: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

宏分为两类

对象宏

对象宏相对比较简单,一般是用来定义一些常数:

#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__ ;当输入零个参数的时候,预处理器会把多出它之前多出的那个逗号去掉。

上一篇 下一篇

猜你喜欢

热点阅读