24H免费课程咨询  TEL:13401595960   QQ:1870218756  微信:13401595960(李老师)

东方博宜

网站首页 > 软件开发资讯 > IOS开发

【常州iOS开发培训班】iOS开发中你真的会用#define么!!!?

2018-05-13 22:00:21 东方博宜 阅读

前言:


不得不说在C系语言(C, Objective-C, C++...)中宏(macro)是个强大的东西, 虽然在基本的语法上面看上去是非常的简单, 不过有时候正因为他的强大和方便, 就会导致在使用的时候, 其中会有很多的注意点, 如果不小心被忽略, 那么将会带来完全不想要的结果. 所以要想灵活的使用它, 那么还是先了解一些比较好. 而且在iOS开发中如果你是使用OC, 那么你可能经常会使用到#define(swift当前不支持宏)


首先扔出几个宏的定义,调用这些宏的时候分别是什么结果, 看看你能够在不看后面的情况下, 清楚多少, 当然, 如果很清楚, 自然可以忽略后文的八卦了..., 因为, 你绝对比我更了解宏...


1. #define PI 3.14

2. #define log(x) printf("this is test: x = %d", x)

3. #define log(x) printf("this is test: "#x" = %d", x)

4. #define power(x) x*x

5. #define RGBA(r, g, b, a) [UIColor colorWithRed:r/255.0f green:g/255.0f blue:b/255.0f alpha:a]

6. #define print(...) printf(__VA_ARGS__)

7. #define RGB(r, g, b)  {\

RGBA(r, g, b, 1.0f);\

}

8. #define weakify( x ) autoreleasepool{} __weak typeof(x) weak##x = x;

9. #define weakify(...) \ autoreleasepool {} \ metamacro_foreach_cxt(rac_weakify_,, __weak, __VA_ARGS__)


这里先不解释上面定义的几个宏了, 首先介绍下宏的一些基本东西


程序第一步是在预编译之前会有一些操作, 例如删除反斜线和换行符的组合, 将每个注释用一个空格替代...


然后在进入预编译的时候, 会寻找可能存在的预处理指定(由#开头), 例如C中常用的#include, 或者oc中的#import, #define...很多(条件编译语句...)


处理#define的时候,然后预处理器会从#开始, 一直到执行到第一个换行符(写代码的时候换行的作用), 自然, #define只会允许定义一行的宏, 不过正因为上面提到的预处理之前会删除反斜线和换行符的组合, 所以可以利用反斜线定义多行宏, 在删除反斜线和换行符的组合后, 逻辑上就成了一行的宏了


宏作用在预编译时期, 其真正的效果就是代码替换, 而且是直接替换(内联函数!!!), 这个和函数有着很大的区别, 并且正因为是直接替换, 在使用的时候就会有一些的注意点了, 这个在后面会给出例子


宏可以被称为 类对象宏, 类函数宏(开篇给的几个宏中都已经囊括了这两类)


定义宏的语法很简单, 一个宏定义由三部分组成 , 三分部之间用空格分开, #define, 宏的名字, 主体 例如第一个宏#define PI(宏的名字) 3.14(主体), 这里有个注意点就是, 宏的命名和普通的变量命名规则相同


宏在预处理阶段只进行文本的替换(相当于把代码拷贝粘贴), 不会进行具体的计算(发生在编译时期)




对于宏的基本的东西就介绍到这里了, 还有一些相关的东西就在下面解释一下上面定义的几个宏的过程中提到


#define PI 3.14 这是宏的最简单的定义了, 可能也是大家应用最广的, 就是使用宏来定义一些常量(消除魔法数字)或字符串...,  这一类可以被称为类对象宏, 方便代码阅读和修改, 使用的时候直接使用定义的宏的名字, PI, 那么预处理器就会将代码中的PI替换为3.14


float computeAreaWithRadius(float r) {

return PI * r * r;

}


#define log(x) printf("this is test: x = %d", x) 这是宏的第二类定义, 即类函数宏, 这一类的宏和函数类似的写法, ( )中可以写变量, 用作函数的参数, 不过, 这个和函数的区别是, 宏的参数不指定类型, 具体的参数类型在调用宏的时候由传入的参数决定(有点其他语言里的泛型的意思), 这个可以算是和函数相比的优点, 下面测试一些这个宏的使用, 结果你猜对了么?


#define log(x) printf("this is test: x = %d", x)

int main(int argc, const char * argv[]) {

int y = 12;

log(y); // 输出为  this is test: x = 12

}


#define log(x) printf("this is test: "#x" = %d", x), 这个定义中和上面的区别是使用了一个#运算符, #运算符被用于利用宏参数创建字符串, 区分一下和上面的结果


#define log(x) printf("this is test: "#x" = %d", x)

int main(int argc, const char * argv[]) {

int y = 12;

log(y);

// 输出为  this is test: y = 12 (而不是 x = 12, 或者 12 = 12)

// 因为使用#和参数结合可以被替换为宏参数对应的字符串, "#x"表示字符串x, 这里输入的参数为y, 则替换为y(不是12)

log(2+4)// 输出为 this is test: 2+4 = 6

}


#define power(x) x*x 这个和上面一样是一个类函数宏, 这里我原本的意愿是计算 x*x即x的平方的值, 不过这样的定义宏在有些情况下是会出问题的, 这个例子就是告诉大家定义类函数宏的时候就真的要小心, 不然客人结果并不是我们预期的 


#define power(x) x*x

int x = 2;

int pow1 = power(x); // pow1 = 2*2 = 4

int pow2 = power(x+1); //  pow2 = 3 * 3 = 9  ??

// 显然对于pow1 = 4是没有问题的

// 不过对于pow2 = 9 这个结果是有问题的, 定义的宏并没有达到我们预想的效果 结果为 3*3

// 因为: 上面提到过宏是直接的代码替换, 这里宏展开后就成为了 x+1*x+1 = 2+1*2+1 = 5

// 这里因为运算优先级的原因导致结果的不一样, 所以pow应该(加上括号)定义为

#define power(x) (x)*(x)


#define RGBA(r, g, b, a) [UIColor colorWithRed:r/255.0f green:g/255.0f blue:b/255.0f alpha:a] 这里是个简单的多参数的类函数宏的定义, 这个宏在使用OC开发的时候 大家可能都会喜欢使用


#define RGB(r, g, b)  {\

RGBA(r, g, b, 1.0f);\

} 这个宏是一个"多行宏"定义的示例, 即在除了最后一行的最后加上反斜线(因为反斜线和换行符的组合在预编译之前会被系统删除), 同时这个宏也说明了, 宏的定义是可以嵌套的(有些编译器可能不支持, xcode中是支持的...)

常州东方博宜是一家专注IT,互联网,电脑方面的顶尖培训机构,欢迎社会及院校有志互联网营销,搜索引擎营销的人士,来东方博宜报名学习,互相交流。

常州东方博宜地址:常州天宁区延陵西路2号工人文化宫5号楼

 2.新北区太湖东路9-4号常州创意园E12


Powered by 东方博宜教育咨询江苏有限公司  ©2008-2018 www.czos.cn