一.编译器
-
编译器是把各种源码转化为计算机可识别的二进制语言的工具.
1.传统的编译器通常分为三个部分,前端(frontEnd),优化器(Optimizer)和后端(backEnd)。
2.这一模型的好处是,当我们要支持多种语言时,只需要添加多个前端就可以了。当需要支持多种目标机器时,只需要添加多个后端就可以了。对于中间的优化器,我们可以使用通用的中间代码。
- 在编译过程中,前端主要负责词法和语法分析,将源代码转化为抽象语法树;
- 优化器则是在前端的基础上,对得到的中间代码进行优化,使代码更加高效;
- 后端则是将已经优化的中间代码转化为针对各自平台的机器代码。
三.预处理的概念
ANSI C标准(ANSI C是美国国家标准协会(ANSI)对C语言发布的标准)规定可以在C源程序中加入一些“预处理命令” ,以改进程序设计环境,提高编程效率。这些预处理命令是由ANSI C统一规定的,但是它不是C语言本身的组成部分,不能直接对它们进行编译,因为编译程序不能识别它们,必须在对程序进行通常的编译之前,先对程序中这些特殊的命令进行处理,这一过程就是我们说的“预处理”。经过预处理后程序可由编译程序对预处理后的源程序进行通常的编译,得到可供执行的目标代码。
在C语言中包括三类预处理指令:1.宏定义 2.条件编译 3.文件包含。
3.1 宏定义
宏定义是用宏名代替一个字符串,只作简单置换,不作正确性检查,同时也不会做运算逻辑处理
- 对程序中用双撇号括起来的字符串内的字符,即使与宏名相同,也不进行置换。
NSLog(@"MAX_INT = %d", 10086)
- 宏定义是专门用于预处理命令的一个专用名词,它与定义变量的含义不同,只作字符替换,不分配内存空间
-
可以用#undef 命令终止宏定义的作用域
终止
3.2 条件编译
条件编译就是在编译之前预处理器根据预处理指令判断对应的条件,如果条件满足就将对应的代码编译进去,否则代码就根本不进入编译环节(相当于根本就没有这段代码)
1、#if 编译预处理中的条件命令, 相当于C语法中的if语句
2、#ifdef 判断某个宏是否被定义, 若已定义, 执行随后的语句
3、#ifndef 与#ifdef相反, 判断某个宏是否未被定义
4、#elif 若#if, #ifdef, #ifndef或前面的#elif条件不满足, 则执行#elif之后的语句, 相当于C语法中的else-if
6、#else 与#if, #ifdef, #ifndef对应, 若这些条件不满足, 则执行#else之后的语句, 相当于C语法中的else
7、#endif #if, #ifdef, #ifndef这些条件命令的结束标志.
8、#if 与 #ifdef 的区别:#if是判断后面的条件语句是否成立,#ifdef是判断某个宏是否被定义过。要区分开!
3.3 文件包含:
C语言下一般使用 #include, OC中一般使用#import ,它们的区别是:在使用#include的时候要注意处理重复引用,#import大部分功能和#include是一样的,但是他处理了重复引用的问题,我们在引用文件的时候不用再去自己进行重复引用处理。OC中还有一个引用声明 @class主要是用于声明一个类,告诉编译器它后面的名字是一个类的名字,而这个类的定义实现是暂时不用知道的。一般来说,在interface中(.h文件)引用一个类,就用@class,它会把这个类作为一个类型来使用,而在实现这个interface的文件中,如果需要引用这个类的实体变量或者方法之类的,还是需要import这个在@class中声明的类。
毛病
2、预处理连接符:#操作符的字符串化和 ##操作符
(1)在含参数宏中,假如希望在字符串中包含宏的参数本身,#符号用作一个预处理运算符,它可以把语言符号转化成字符串该过程称为字符串化(stringizing)。
//定义含参宏
#define MAX_TAG(maxTag) NSLog(@"the max tag "#maxTag" %d", maxTag *3)
-----------------------------------------------------------------------
// 调用
MAX_TAG(33);
-----------------------------------------------------------------------
//打印结果为
2016-11-29 10:53:45.655 SpeachTest[2294:271425] the max tag 33 99
(2)# #操作符结合了两种标记成一个token,该标记可以替代部分字符串。
#define MMM(a) a ## Button
--------------------------------------------------------------------
NSString * MMM(title) = @"asd";
NSLog(@"titleButton = %@",MMM(title));
NSLog(@"titleButton = %@", titleButton);
--------------------------------------------------------------------
//打印的结果
2016-11-29 10:57:27.364 SpeachTest[2179:233773] titleButton = asd
2016-11-29 10:57:27.367 SpeachTest[2179:233773] titleButton = asd
在这里我并没有直接定义“titleButton”,但是打印titleButton不但不报错而且titleButton已经定义过了。 titleButton其实就是MMM(title),这就是##的作用,大家可以试一下。
3、在宏定义中换行
只需要在每行的结尾添加反斜杠“\”
#define SHOWALERT(m)\
{\
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@" 提 示 " message:m delegate:nil cancelButtonTitle:@"确认" otherButtonTitles:nil];\
[alert show];\
}\
4、 defined()函数 与 #if等条件条件编译函数的应用
#define aaa "i am aaa"
#if ( defined(aaa) && !defined(bbb) )
#define bbb "i am bbb"
#else
#define bbb "i am bbb_2"
#endif
打印bbb的结果:
图片.png5、 省略号···和 VA_ARGS
关于省略号··· 代表的是个数可变的参数即可变参数,一般会与__VA__ARGS__
结合使用,__VA__ARGS__
表示保留名,将省略号省略的参数传递给宏。
// 例如我们最常见的形式
#ifdef DEBUG
#define JRLog(...) NSLog(__VA_ARGS__)
#else
#define JRLog(...)// 如果编译经过在这里那么JRLog(···)无意义
#endif
还有当含参数宏的参数至少有一个时:
#ifdef DEBUG
#define JRLog(aaa, ...) NSLog(aaa, ##__VA_ARGS__)
#else
#define JRLog(...)
#endif
此时##的作用是在可变参数被忽略或为空的情况下,‘##’操作将使预处理器去除掉“···”前面的那个逗号。
- 特别注意:省略号···只能出现在参数的最后面,放在其他参数中间或者前面是不可以的!
6、iOS常用的系统内参数宏
// 判断是否是真机
#if TARGET_OS_IPHONE // 在这里一定不能使用#ifdef,因为TARGET_OS_IPHONE无论在真机还是模拟器情况下都存在只不过 模拟器时值为0
#else
#endif
// 判断是否是模拟器
#if TARGET_OS_SIMULATOR // 同上。"TARGET_IPHONE_SIMULATOR"已经废弃
#else
#endif
// 判断手机系统版本
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_9_0
#else
#endif
// 规定只能在ios系统下运行
#ifdef __IPHONE_OS_VERSION_MIN_REQUIRED
// 规定运行支持的最小版本
#if __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_7_0
#else
#endif
#endif
网友评论