预处理
C语言的预处理(预编译)主要有三个方面的内容: 1.宏定义; 2.文件包含; 3.条件编译。“#”是编译器预处理的标志。
预处理(预编译)工作也叫做宏展开:将宏名替换为文本(这个文本可以是字符串、可以是代码等)。
掌握"宏"概念的关键是“换”。
1.宏定义
:预处理阶段会将程序中所有用到宏定义的地方替换成原内容。因此,使用宏定义可以减少代码量,保持一致性,使开发过程更轻松。
2.文件包含
:指的是头文件的引入,在预编译阶段会把引入头文件的内容拷贝至当前文件中。
#import "ClassA.h"
#import <Foundation/Foundation.h>
3.条件编译
:预编译时可以根据条件来决定编译哪块代码,可以减少编译的代码量
条件编译指令 | 释义 |
---|---|
#undef | 取消已定义的宏 |
#if | 判断表达式真假 |
#ifdef | 如果宏已经定义 |
#ifndef | 如果宏没有定义 |
#elif | 上边表达式不成立时,判断当前表达式是否成立 |
#endif | 结束一个#if……#else条件编译块 |
宏定义
上边简单的提了一下宏定义,这里重点记录下宏定义一些语法和用法。
- 无参宏(直接带过)
#define NUMBER 100
#define NOTIFICATION_CENTER [NSNotificationCenter defaultCenter]
- 带参宏
- 固定参数
如果让你实现一个取最小值的宏函数,你一定觉的很简单,然后胸有成竹的就写出了这行代码
#define MIN(A,B) A < B ? A : B
看着逻辑上也没有什么毛病,嚯嚯嚯,小伙子,入坑了吧!我们知道预处理会在预编译阶段将预定义标识替换成原内容,如果有宏嵌套,宏展开后,原先的逻辑可能会因为运算符的优先级导致输出错误。具体详解请看大神之作《宏定义的黑魔法 - 宏菜鸟起飞手册》。
正确写法:(这真的不是一般的麻烦啊。。。)
#define MIN(A,B) ({ __typeof__(A)__a = (A); __typeof__(B) __b = (B); __a < __b ? __a :__b; })
- 可变参数及特殊语法
特殊标识 | 释义 | 示例 |
---|---|---|
# | 单个”#“号的作用是字符串化 | #define A(x) #x 调用 A(123) 将得到c字符串 "123" |
@ | @是objc的编译符号,不属于宏操作的对象 | #define A(x) @#x 将得到OC字符串 @"123" |
\ | 连接换行符 | 放在行尾 然后换行 用来连接代码块 |
## | 双井号是连接符 | #define A(x,y) x##y 调用 A(123,456) ==> 123456 |
__ | 双下滑线表示预定义,即已经定义过的 | __TIME__, __FUNCTION__, __LINE__ 等 |
... | 任意个数的参数,但是宏定义中只有... ,那么起码有1个参数 | #define NSLog(...) {(NSLog)((format),__VAR_VACHS__);} |
__VA_ARHS__ | 配合...使用,表示的是宏定义中的...中的所有剩余参数,至少一个 | 同上 |
##__VA_ARHS__ | 参数个数不限制,可为0 | #define NSLog(format, ...) {(NSLog)((format),##__VAR_VACHS__);} |
宏定义示例
单例
#define RF_SINGLETION(__clazz) \
+ (__clazz *)sharedInstance;
#define RF_DEF_SINGLETION(__clazz) \
static __clazz * __singletion;\
+ (__clazz *)sharedInstance \
{\
static dispatch_once_t once; \
dispatch_once(&once,^{__singletion = [[__clazz alloc] init];});\
return __singletion;\
}\
+ (id)allocWithZone:(struct _NSZone *)zone {\
\
if (!__singletion) {\
\
return [super allocWithZone: zone];\
\
}\
\
return nil;\
\
}\
\
- (id)copy {\
\
return __singletion;\
\
}\
初始化方法
#define INIT_CELL(_CLASS_NAME) \
\
- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier \
{ \
NSLog(@"-------------- %@ init ----------", self.class); \
[_CLASS_NAME description]; \
if ((self = [super initWithStyle:style reuseIdentifier:reuseIdentifier])) { \
[self _CLASS_NAME##_internalInit]; \
} \
\
return self; \
} \
\
- (void)awakeFromNib \
{ \
[super awakeFromNib]; \
\
[self _CLASS_NAME##_internalInit]; \
} \
\
- (void)_CLASS_NAME##_internalInit
结语
本篇为知识总结,帮助自己查阅资料,后续会不断更新。。。祝大家学习愉快!^_^
网友评论