iOS预编译指令详解

1.预处理的概念

ANSI C标准(ANSI C是美国国家标准协会(ANSI)对C语言发布的标准)规定可以在C源程序中加入一些“预处理命令” ,以改进程序设计环境,提高编程效率。这些预处理命令是由ANSI C统一规定的,但是它不是C语言本身的组成部分,不能直接对它们进行编译,因为编译程序不能识别它们,必须在对程序进行通常的编译之前,先对程序中这些特殊的命令进行处理,这一过程就是我们说的“预处理”。经过预处理后程序可由编译程序对预处理后的源程序进行通常的编译,得到可供执行的目标代码。

2.预处理指令功能

在C语言中包括三类预处理指令:1.宏定义 2.条件编译 3.文件包含。

宏定义:

(1)宏的定义

定义格式: #define 标识符 字符串
1、 不含参数: #define TAG_VIEW 10086
2、 含有参数:#define MAX_INT(a,b) a+b

(2)宏定义的说明

1、宏名一般习惯用大写字母表示,以便与变量名相区别。但这并非规定,也可用小写字母。
2、 宏定义是用宏名代替一个字符串,只作简单置换,不作正确性检查,同时也不会做运算逻辑处理,同时在进行宏定义时,可以引用已定义的宏名,可以层层置换。(在这里需要特别注意的是:当宏涉运算时,要根据情况来添加括号,防止运算逻辑出现错误,如下图所示,当你宏MAX_TXT想作为整体来使用时应该写成这样: #define MAX_INT (2+3) 这样MAX_END的结果应该是25,如果不加括号,只会进行置换行为,MAX_END的结果就为11。在这非常感谢 @星星月亮落一地 的提醒)


3、 宏定义不是C语句,不必在行末加分号。如果加了分号则会连分号一起进行置换。
4、 #define 命令出现在程序中函数的外面,宏名的有效范围为定义命令之后到本文件结束。通常,#define 命令写在文件开头,函数之前,作为文件一部分,在此文件范围内有效。
5、 可以用
#undef
命令终止宏定义的作用域。

6、对程序中用双撇号括起来的字符串内的字符,即使与宏名相同,也不进行置换。NSLog(@"MAX_INT = %d", 10086)
7、宏定义是专门用于预处理命令的一个专用名词,它与定义变量的含义不同,只作字符替换,不分配内存空间。

条件编译:

条件编译就是在编译之前预处理器根据预处理指令判断对应的条件,如果条件满足就将对应的代码编译进去,否则代码就根本不进入编译环节(相当于根本就没有这段代码)。

常用条件编译函数

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是判断某个宏是否被定义过。要区分开!

#ifdef  MAX_F
// 如果定义了宏MAX_F,则编译此处的代码
#else
// 如果没有定义宏MAX_F,则编译此处的代码
#endif

// 同样
#ifndef  MAX_F
// 如果没有定义宏MAX_F,则编译此处的代码
#elif MAX_INT
// 如果定义了宏MAX_F,同时还定义了宏MAX_INT,则编译此处的代码
#else
// 定义了宏MAX_F,但是没有定义宏MAX_INT,则编译此处的代码
#endif

另外,在创建一个头文件或pch文件 --- 单独的一个.h文件时,常看到文件内自带了下述格式内容

#ifndef Header_h 
#define Header_h 

#endif

上面的格式是为了防止该头文件被引用时发生重复引用。

文件包含:

C语言下一般使用 #include, OC中一般使用#import ,它们的区别是:在使用#include的时候要注意处理重复引用,#import大部分功能和#include是一样的,但是他处理了重复引用的问题,我们在引用文件的时候不用再去自己进行重复引用处理。OC中还有一个引用声明 @class主要是用于声明一个类,告诉编译器它后面的名字是一个类的名字,而这个类的定义实现是暂时不用知道的。一般来说,在interface中(.h文件)引用一个类,就用@class,它会把这个类作为一个类型来使用,而在实现这个interface的文件中,如果需要引用这个类的实体变量或者方法之类的,还是需要import这个在@class中声明的类。

3.关于宏的灵活使用和拓展:

1、在宏中拼接新的宏(限字符串)

(1)OC的代码写法:

#define aaa @"i am aaa"
#define bbb @"i am bbb"
#define  ccc @""bbb@" "aaa@""

打印ccc的结果如下


(2)C的写法

#define aaa "i am aaa"
#define bbb "i am bbb"
#define  ccc ""bbb" "aaa""

打印结果是一样的。

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的结果:


5、 省略号···和 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
// 可以参照Availability.h 文件  文件路径 /Applications/Xcode8.1.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/usr/include 不同Xcode版本路径略有差异
/**
 #define __IPHONE_2_0      20000
 #define __IPHONE_2_1      20100
 #define __IPHONE_2_2      20200
 #define __IPHONE_3_0      30000
 #define __IPHONE_3_1      30100
 #define __IPHONE_3_2      30200
 #define __IPHONE_4_0      40000
 #define __IPHONE_4_1      40100
 #define __IPHONE_4_2      40200
 #define __IPHONE_4_3      40300
 #define __IPHONE_5_0      50000
 #define __IPHONE_5_1      50100
 #define __IPHONE_6_0      60000
 #define __IPHONE_6_1      60100
 #define __IPHONE_7_0      70000
 #define __IPHONE_7_1      70100
 #define __IPHONE_8_0      80000
 #define __IPHONE_8_1      80100
 #define __IPHONE_8_2      80200
 #define __IPHONE_8_3      80300
 #define __IPHONE_8_4      80400
 #define __IPHONE_9_0      90000
 #define __IPHONE_9_1      90100
 #define __IPHONE_9_2      90200
 #define __IPHONE_9_3      90300
 #define __IPHONE_10_0    100000
 #define __IPHONE_10_1    100100
 */

开发常用的一些宏定义网上有很多,这里就不一一列举了,希望对读者有帮助。

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

推荐阅读更多精彩内容

  • 目录 一.预处理的工作方式... 3 1.1.预处理的功能... 3 1.2预处理的工作方式... 3 二.预处理...
    朱森阅读 1,335评论 0 2
  • C中的预编译宏定义 2009-02-10 作者: infobillows 来源:网络 在将一个C源程序转换为可执行...
    白水灬煮一切阅读 1,569评论 0 5
  • 在源代码的编译过程中,会需要一些机制来完成以下的一些功能:在编译时包含其他源文件、定义宏、根据条件决定编译时是否包...
    赵亦晨阅读 538评论 0 0
  • 文/孤鸟差鱼 不要东拉西扯 别折磨打吊瓶的人
    孤鸟差鱼阅读 169评论 0 2
  • 今天你是否会想起,昨天学医的你;明天你是否会惦记,这个温暖的群体!二十年之后的同学,都已改变模样;虽然有各自的事业...
    关中刀客阅读 216评论 0 0