Objective-C 预处理指令 #

作者: zedds | 来源:发表于2017-08-19 16:52 被阅读0次

预处理指令是以 # 号开头的代码行。#号必须是该行除了任何空白字符外的第一个字符。# 后是指令关键字,在关键字和#号之间允许存在任意个数的空白字符。整行语句构成了一条预处理指令,该指令将在编译器进行编译之前对源代码做某些转换。

#                 // 空指令,无任何效果
#import “"        // 导入一个源代码文件      
#include “”       // 包含一个源代码文件
#define macro     // 定义宏
#undef macro      // 取消定义宏
#if condition     // 条件编译指令,如果满足condition,则编译以下内容
#ifdef            // 条件编译指令,如果定义了,则往下编译
#ifndef           // 条件编译指令,如果没有定义,则往下编译
#elif             // 如果前面的 #if 不为真,当前条件为真,则往下编译
#endif            // 结束条件编译块
#error            // 停止编译,并显示错误信息,一般用于条件编译
  • 导入/包含文件

    #import#include 大部分功能是一样的,但是他处理了重复引用的问题,我们在引用文件的时候不用再去自己进行重复引用处理。

    例如:有 A.h B.h C.h三个头文件
    A.h需要引入B.h 和 C.h, 而B.h也引入C.h 这样就构成了重复引用,使用#import就可以避免这种情况。

    有两种引入方式,一种使用尖括号< >,告诉编译器在编译器自带的或外部库的头文件中搜索被包含的头文件,另一种使用双引号"" ,表示在当前被编译的应用程序的源代码文件中搜索被包含的头文件,如果找不 到,再搜索编译器自带的头文件。

    在OC中应尽量少在类的头文件中引入其他头文件,如果需要在头文件中用到引入的头文件,首先考虑向前声明(forward declaring),将引入头文件的时机尽量延后,只有在有需要时才引入。

    @class YourClass
    

    在这种不需要知道 YourClass 类的全部细节,只需要知道有一个类名叫 YourClass 就好的情况下,使用向前声明可以减少编译时间,提高效率。

    然而有些协议,比如“委托协议”就需要知道协议内容,这时候不能使用向前声明,应该考虑在类的扩展 class-continuation category 中实现,这样的话需要在实现文件中引入包含的委托协议头文件即可,而不需要将其放在公共头文件中。

    要点:

    1. 除非有必要,否则不要引入头文件,一般来说,应在某个类的头文件中使用向前声明来提及别的类,并在实现文件中引入那些类的头文件。这样做可以尽量降低类之间的耦合。
    2. 有时无法使用向前声明,比如要声明某个类遵循意一项协议,这种情况下,尽量把该类遵循的某协议的这条声明移至 class-continuation category中。如果不行的话,就把协议单独放在一个头文件中,然后将其引入。
  • 宏定义

    #define 定义一个宏,用 #undef 取消定义一个宏,宏的定义在编译时只是简单的替换

    #define TEST_MACRO 100       // 定义宏  
    int array[TEST_MACRO];       // 使用定义的宏
    #undef TRST_MACRO            // 取消定义宏
    #define VALUE1 10
    #define VALUE2 20
    #define VALUE (VALUE1 + VALUE2)
    

    注意:
    定义宏常用大写字母作为宏名
    在定义宏的时候,后面如果有计算,习惯于使用括号
    宏定义可以定义一个函数 例如:

    #define SQUARE(x) (x * x)
    int square = SQUARE(5);
    
  • # 运算符
    # 运算符将参数转换为一个字符串 例如:

    #define TEST(n) @"SHIT"#n
    NSLog(@"%@",TEST(ON));  // 此时将ON作为字符串拼接到“SHIT”后面
    

    控制台输出为

    2017-08-19 15:02:30.165640+0800 VowelMovement[7289:370495] SHITON
    Program ended with exit code: 0
    
  • ## 运算符
    ## 运算符的作用是将出现在其两侧的参数合并 例如:

    #define TEST(x, y, z) x##y##z
    NSLog(@"%d", TEST(1, 2, 3));
    

    控制台输出结果

    2017-08-19 15:08:32.405656+0800 VowelMovement[7336:375139] 123
    Program ended with exit code: 0
    
  • 条件编译指令

    1. #if指令:检测跟在制造另关键字后的常量表达式。如果表达式为真,则编译后面的代码,知道出现#else#elif#endif为止;否则就不编译。

    2. #endif用于终止#if预处理指令

    3. #ifdef#ifndef : #ifdefined 等价于 #ifdef ; #ifdefined等价于#ifndef

    4. #else指令用于某个#if指令之后,当前面的#if指令的条件不为真时,就编译#else后面的代码。#endif指令将中指上面的条件块。

    5. #elif预处理指令综合了 #else#if指令的作用。

      #ifdef TEST
              printf("defined TEST");
      #else
              printf("no define");
      #endif
      

Reference:
《Effective Objective-C 2.0 编写高质量iOS与OS X代码的52个有效方法》

相关文章

  • Objective-C总结----6.预编译指令

    Objective-C编程语言中含有一个预处理器,用于在编译前处理源文件。 预处理器语言预处理器指令宏展开 预处理...

  • 【OC梳理】预处理指令

    预处理指令,就是我们常说的宏定义。在编译器对 C或者 objective-c 进行编译前,编译器会对这些预处理命令...

  • 读书笔记 - 《Effective Objective-C 2.

    第 1 章 熟悉 Objective-C 1.少用 #define 预处理指令,尽量在实现文件中使用 static...

  • Objective-C 预处理指令 #

    预处理指令是以 # 号开头的代码行。#号必须是该行除了任何空白字符外的第一个字符。# 后是指令关键字,在关键字和#...

  • C语言 枚举类型和预处理指令

    枚举的定义 预处理指令 所有的预处理指令都是以#开头 预处理指令分为三种 宏定义 条件编译 文件包含 预处理指令在...

  • Objective-C源文件编译过程

    简介 Objective-C文件的编译过程主要包括clang前端的预处理、编译、后端优化中间表示、生成汇编指令、链...

  • OC 编译过程

    Objective-C文件的编译过程主要包括clang前端的预处理、编译、后端优化中间表示、生成汇编指令、链接、生...

  • 面向对象(三十三)-预处理指令

    什么是预处理指令预处理器指令指导编译器在实际编译开始之前对信息进行预处理。预处理指令注意点所有的预处理器指令都是以...

  • 《Effective Objective-C 20 编写高质量i

    第1章:熟悉Objective-C 第4条:多用类型常量,少用#define预处理指令 声明类型常量好处是,编译器...

  • C和指针——简介篇

    程序示例 预处理指令 以上5行都为预处理指令。因为它们是由预处理器解释的。预处理器读入源代码,根据预处理指令对其进...

网友评论

    本文标题:Objective-C 预处理指令 #

    本文链接:https://www.haomeiwen.com/subject/qnitdxtx.html