这是我参与8月更文挑战的第16天,活动详情查看: 8月更文挑战
1、何为宏定义?
宏定义是C语言
提供的三种预处理功能的其中一种,这三种预处理包括:宏定义
、文件包
含、条件编
译。在IOS
中我们经常看到很多宏定义
的代码,即使是在苹果的官方文档中宏定义
也占据很大位置。
2、宏定义的使用
宏定义又称为宏代换、宏替换,简称“宏”。
格式:
#define 标识符 字符串
其中的标识符就是所谓的符号常量,也称为宏名。
预处理(预编译)工作也叫做宏展开
:将宏名替换为字符串。
掌握宏
概念的关键是换
。一切以换为前提、做任何事情之前先要换,准确理解之前就要“换”。
即在对相关命令或语句的含义和功能作具体分析之前就要换:
例:
#define Pi 3.1415926
把程序中出现的
Pi
全部换成3.1415926
说明:
- (1)宏名一般用
大写
- (2)使用宏可提高程序的
通用性
和易读性
,减少不一致性,减少输入错误和便于修改。例如:数组大小常用宏定义 - (3)
预处理
是在编译
之前的处理,而编译工作的任务之一就是语法检查
,预处理不做语法检查。 - (4)宏定义末尾不加分号;
- (5)宏定义写在函数的花括号外边,作用域为其后的程序,通常在文件的最开头。
- (6)可以用
#undef
命令终止宏定义的作用域 - (7)宏定义允许嵌套
- (8)字符串
" "
中永远不包含宏 - (9)宏定义不分配内存,变量定义分配内存。
- (10)宏定义不存在类型问题,它的参数也是无类型的。
3、宏定义的优缺点
优点:
- (1)提高了程序的
可读性
,同时也方便修改 - (2)提高程序的运行效率,使用带参数的宏定义即可完成函数调用的功能,又能避免函数的岀栈与入栈操作,减少系统开销,提高运行效率
- (3)宏是由
预处理器
处理的,通过字符串操作可以完成很多编译器无法实现的功能,比如##链接符
缺点:
- (1)由于是直接嵌入的,所以代码可能相对多一点
- (2)嵌套定义过多可能会影响程序的
可读性
,而且很容易出错 - (3)带参数的
宏
而言,由于是直接替换,并不会检查参数是否合法,存在安全隐患
补充:
预编译
语句仅仅是简单的值代替
,缺乏类型
的检测机制,这样预处理语句就不能享受C++
严格的类型检查的好处,从而可能成为引发一系列错误的隐患。
最后引用《C陷进与缺陷》的一句话,对其进行总结:
宏并不是函数,宏并不是语句,宏并不是类型定义
4、常量宏定义替换方案const
const
用法:一般常用的字符串定义成const
(对于常量字符串苹果推荐我们使用const
)
5、宏与const的区别:
- (1)编译时刻不同,宏属于预编译,const属于编译时刻
- (2)宏能定义代码,const不能,多个宏对于编译会相对时间较长,影响开发效率,调试过慢,const只会编译一次,缩短编译时间。
- (3)宏不会检查错误,const会检查错误
6、内联函数的介绍
内联函数从源代码层看,有函数结构,而在编译后,却不具备函数性质,内联函数不是在调用时发生控制转移,而是在编译时将函数体嵌入每一个调用处,编译时,类似宏替换,使用函数体替换调用处的函数名,在代码中用inline关键字修饰,在类中声明的成员函数,自动转换为内联函数;
- 类中的成员函数默认是内联函数(要求成员函数没有循环和递归,当其中存在循环的递归的时候,编译器会将其默认为一个普通函数处理)
- 内联函数不允许有循环或者递归语句
- 内联函数的定义必须出现在第一次调用内联函数之前
比如:
#pragma mark 判断设备是否是iPhone X
static inline BOOL iPhoneX() {
BOOL iPhoneXSeries = NO;
if (UIDevice.currentDevice.userInterfaceIdiom != UIUserInterfaceIdiomPhone) {
return iPhoneXSeries;
}
if (@available(iOS 11.0, *)) {
UIWindow *window = [[[UIApplication sharedApplication] delegate] window];
if (window.safeAreaInsets.bottom > 0.0) {
iPhoneXSeries = YES;
}
}
return iPhoneXSeries;
}
7、内联函数的优缺点
优点:
- 有参数类型检测,更加安全
- 内联函数是在程序运行时展开,而且是进行参数传递
- inline关键字只是对编译器的一个定义,如果函数本地不符合内联函数的标准,编译器就会将这个函数当作是普通函数
缺点:
- 因为内联函数是在调用处展开,所以会使代码边长,占用更多内存
8、内联函数与宏的区别
- 内联函数在运行时可调试,而宏定义不可以
- 编译器会对内联函数的参数类型做安全检查或自动类型转换,而宏定义则不会
- 内联函数可以访问类的成员变量,而宏定义则不能
通过以上对比,我们以后在开发中如果定义一个常量字符串可以用const,定义代码就是用宏或者内联函数;