iOS-#define详解

前言

宏(#define)在C系开发中可以说占有举足轻重的作用。底层框架自不必说,为了编译优化和方便,以及跨平台能力,宏(#define)被大量使用,可以说底层开发离开宏(#define)将寸步难行。

不得不说在C系语言(C、Objective-C、C++等)中宏(#define)真是个非常方便又强大的东西。

宏(#define)在基本的语法上是非常的简单的,但完全不会影响它的强大。

不过有时候正因为宏(#define)的简单、方便和强大,就会导致我们平常在使用的时候,其中会有很多的注意点和细节需要我们去注意,如果不小心将其忽略, 那么可能会带来我们意料之外的不想要的结果。

如果我们要想灵活的使用宏(#define),那么深入了解宏(#define)工作原理和用法必不可少。

而且经常在iOS开发中使用Objective-C, 那么肯定会经常使用到宏(#define)。

预编译 

程序会在预编译之前还会有一些操作, 比如:删除反斜线+换行符的组合, 将各种形式的注释用空格替代等等。

接着是预编译阶段,预编译在处理#define的时候,会从#开始一直执行到遇到的第一个换行符(写代码的时候换行的作用)为止。

所以可知#define只会允许定义一行的宏,但是因为预编译之前会删除反斜线+换行符的组合,所以我们可以利用反斜线+换行符来定义多行宏,在将删除反斜线和换行符的组合后,在预编译阶段的逻辑上#define定义就成了一行的宏了。

#define在预处理阶段只进行文本的替换(相当于把代码拷贝粘贴),不会进行具体的计算。

#define作用在预编译时期,其真正的效果就是代码替换,而且是直接替换(内联函数!!!),这个和函数有着很大的区别。

宏(#define)的基本语法:

#define 宏名 主体;
   ↓   ↓    ↓
#define PI  3.1415926

宏(#define)的使用:

类对象宏:

类对象宏一般用来定义数据常量或字符串常量。

#define PI  3.1415926

#define NAME @"SunSatan"

类函数宏:

类函数宏就是宏名类似函数名,宏的主体为函数,并可以帮助主体函数接受参数,使用起来就像是函数一样。

#define Log(x) NSLog(@"this is test: x = %@", x)

类函数宏和函数的区别是, 类函数宏的参数不指定类型, 具体的参数类型在调用宏的时候由传入的参数决定,这就可能会遇到类型错误的问题。

举个栗子:

#define power(x) x*x

int x = 2;
int pow_1 = power(x);
int pow_2 = power(x+1);

猜猜pow_1和pow_2的值分别为多少?

结果是pow_1=4 ,pow_2=5。

这个结果是不是和预想的不一样,pow_2不应该等于9吗?因为宏真正的效果就是代码替换,所以在预编译后原来的代码变为了:

#define power(x) x*x

int x = 2;
int pow_1 = x*x;    //2*2=4
int pow_2 = x+1*x+1;//2+1*2+1=5

这样看是不是就能看出问题,在代码替换后优先级不对了。

所以想要得到正确的结果的宏定义如下:

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

这个栗子就是告诉大家定义类函数宏的时候就真的要小心,不然得到结果可能会出乎我们的意料。

宏(#define)中操作符的使用:

#:字符串化操作符,需要放置在参数前,将类函数宏中传入的参数用""括起来变成了c语言的字符串。

#define Log(x) #x

代码替换后:
Log(x) -> "x"

所以以下两种使用方法都没问题,打印信息都是 x
NSLog(@"%s", Log(x)); -> NSLog(@"%s", "x");
NSLog(@"%@",@Log(x)); -> NSLog(@"%@",@"x");

##:符号连接操作符,需要放置在参数前,参数就会和##前面的符号连接起来。

#define single(name) +(instancetype)share##name;

代码替换后:
single(SunSatan) -> +(instancetype)shareSunSatan;

宏(#define)的好处:

使用宏的好处是不言自明的,可以少写很多重复的代码,修改一处就可以完成全局修改,在节省工作量的同时,大大增加代码可读性。

如果想成为一个能写出漂亮优雅代码的开发者,宏绝对是必不可少的技能。

使用宏(#define)的建议:

多多使用类函数宏对开发者而言是非常灵活、方便的,可以抽离很多重复使用的冗长的代码段,增加代码可读性,节省工作量。

使用但不是滥用,应有节制。

使用大量的宏,每次修改宏都需要重新替换,导致编译时间久。

不建议使用类对象宏,因为类对象宏定义的是常量,既然都要定义为常量,那么我们应该使用const来修饰。

相对于定义常量而言,const要比宏效率高很多,而且宏不做检查,只是代码替换,而const会进行编译检查,const要比宏更安全。所以应尽可能的使用const来代替类对象宏。

猜你喜欢

转载自blog.csdn.net/qq_36557133/article/details/86476686