Objective-C中的预处理器指令与宏

什么是预处理器,跟我有什么关系?

预处理器是在OC源文件编译过程中的一个部分,而且是第一个处理部分,预处理器的预也由此可见。

整个编译过程可以大致分为:预处理器进行词法分析 -> 语法分析 -> 生成代码和优化 -> 生成可执行的二进制文件。

既然有这么多过程,为什么要关注预处理器呢?因为它在我们的开发中最常见,而且每个iOS开发者一定都见过。

不信的话我们可以列举一下常见的预处理指令,预处理器有其区别于Objective-C的独特语法,语法形式如下:

#指令名 指令参数

有点眼熟了?我们再具体地说说包含哪些:

  • 头文件包含(#include、#import)
  • 条件编译(#if、#elif、#else、#endif、#ifdef和#ifndef)
  • 诊断(#error、#warning和#line)
  • pragma指令

这样列出来就明白了吧,早说是这些就简单了嘛,大部分都是熟人,慢着,这些熟悉的具体表示什么?有什么区别?那些不太熟的又是干什么的呢?我们一个个来看。

除了上述的指令外,还有一个老熟人也属于预处理器的范畴,下文再来说。

预处理器指令

头文件包含

学C语言的时候就接触到了#include,学java也会用到import(注意没有#号),都是用来导入头文件的,这个作用我们明白,OC中的导入头文件有#include和#import两种指令,而且对于头文件名还分为双引号包含和尖括号包含两种方式:

#include "头文件名"

#include <头文件名>

#import "头文件名"

#import <头文件名>

问题来了,有啥区别?

先说双引号和尖括号的区别,双引号封装头文件名时,会先从存储要编译的这个文件的目录中去搜索包含的头文件,找不到再去用来搜索系统标准头文件的默认目录搜索。而尖括号封装头文件名时,会直接去用来搜索系统标准头文件的默认目录搜索。由此可见,要用尖括号封装标准头文件,而自己写的OC类头文件,应该用双引号封装。

而对于#include和#import这两者,区别在于#import可以确保头文件只被引用一次,这样就可以防止递归包含,什么叫递归包含,A引用B和C,B也引用了C,那就都包含了C,这就重复包含了。因此,如果非要用#include,那必须额外地写指令来判断有没有包含过,来避免递归包含。

条件编译

条件编译特别像我们在所有编程语言中都能看到的 if ... else if ... else 形式,也就是条件判断语句。

用法如下
#if(对应于if)
// 执行内容
#elif(对应于else if)
// 执行内容
#else(对应于else)
// 执行内容
#endif

对于各个语句的用法要求也和一般语言相同,特殊的是最底下有一个#endif,毕竟没有大括号也没有缩进嘛,而且支持嵌套操作,那嵌套的界限就更要靠#endif来判断了对吧。

除了这些以外,还有两个:

#ifdef 宏名
// 执行内容
#endif

#ifndef 宏名
// 执行内容
#endif

其中的def是define的简写,ndef也就是not define,很容易猜到意思,分别就是判断是否定义过后面跟着的宏。同样的要用#endif来作为结束的界限。

诊断

诊断中先说头两个:

#ifndef 宏名
#error "发生错误啦"
#endif

#if XXX
#warning "警报!警报!"
#endif

一般都用在条件判断语句内容中,后面都跟着双引号带着的消息,error指令会直接中止编译,抛出错误消息,warning也会抛出警告消息,但不会中止编译。

第三种诊断指令:

#line 行号 "文件名"
//假设这里有一行会发生错误的代码

这个指令理解起来有些复杂,首先line定义了一个行号,那么之后每一行都会有一个在此基础上依次加一的行号,比如下一行的错误代码就是第11行。发生错误后,会抛出说"文件名"文件的第11行有错误。后面跟着的文件名是一个可选项,写了就可以在消息中显示,不写也没关系。

#pragma指令

这个指令更常见了,我们使用UITableView的时候,经常会用到:

#pragma mark - UITableView DataSource
……
#pragma mark - UITableView Delegate
……

这个#pragma mark指令可以在Xcode 中的该文件的方法列表中插入标记,#pragma mark -就可以插入一个分隔线,后跟文字就可以插入文字标签。

除此之外,#pragma指令还包含很多别的选项,上面的是用的最多的,其他的可以查看文档。

预处理器之宏

要知道,宏也是预处理器范畴内的内容,我们用的也很多:

// 定义常量值
#define 宏名 值
//定义函数宏
#define 宏名(参数) 代码

// 移除宏
#undef 宏名

宏被定义后,会一直存在,并且能在整个文件中起作用,直到被#undef指令移除为止。如果函数有多个参数,用逗号分隔开。

定义函数宏的时候,有一个细节要注意,就是要多对参数使用括号:

#defind SQUARE(x) ((x) * (x))

为什么要这么麻烦?为什么不能直接 x * x?要知道,宏在这个意义上是很“傻”的,它只会单纯的将你输入的x值拿去替换函数代码中的x,并不会做什么处理,所以如果你这样输入就会造成没有意料到的结果:

#defind SQUARE(x) x * x

int number = SQUARE(4+2);// 你以为会等于36?并不会

// 我们说了,宏只会简单替换,所以上面等价于:

int number = 4 + 2 * 4 + 2;// 其实等于14

知道问题所在了吧,这很严重,因为不知道的话根本无法理解这个bug为什么会出现,所以都应该使用括号。此外,如果你的代码有多行,还应该使用大括号括起来:

#define FUNC(a, b) {a = a + b; b = a - b;}

此外,不要过度使用宏!宏很强大,也很危险,出了问题往往难以诊断,也不好维护。

以上就是OC编译中的预处理器中的一些预处理语言函数的内容,预处理器的内容当然不单单只有这些,还有对源文件的一些处理,但这些是我们平常开发中经常遇到的,了解他们是必须且重要的。


查看作者首页

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,417评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,921评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,850评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,945评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,069评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,188评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,239评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,994评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,409评论 1 304
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,735评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,898评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,578评论 4 336
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,205评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,916评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,156评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,722评论 2 363
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,781评论 2 351

推荐阅读更多精彩内容

  • 目录 一.预处理的工作方式... 3 1.1.预处理的功能... 3 1.2预处理的工作方式... 3 二.预处理...
    朱森阅读 1,364评论 0 2
  • C中的预编译宏定义 2009-02-10 作者: infobillows 来源:网络 在将一个C源程序转换为可执行...
    白水灬煮一切阅读 1,583评论 0 5
  • 在实际开发中,有时候在编译之前还需要对源文件进行简单的处理。例如,我们希望自己的程序在Windows和Linux下...
    凡眼观世界阅读 857评论 1 0
  • 对你最沉默的时候 是以为你会暗暗关心 结果却是一通气的发泄
    小小纸飞机阅读 162评论 0 0
  • 即将进入耄耋之年、身体也依旧健康的琼瑶阿姨,前几天写下了“生前遗嘱”,以公开信的形式,表达了“尊严死”的意愿。她甚...
    Runningapple阅读 340评论 0 0