Objective-C 预处理

  • 预处理

    Objective-C 预处理器不是编译器的一部分,而是编译过程中的一个单独的步骤。用简单的术语来说,Objective-C 预处理器只是一个文本替换工具,它指示编译器在实际编译之前进行必要的预处理。我们将Objective-C 预处理器称为OCPP。所有的预处理器命令都以磅符号(#)开头。它必须是第一个非空白字符,为了可读性,预处理器指令应该从第一列开始。下面的部分列出了所有重要的预处理器指令
    预处理器 说明
    #define 替代预处理器宏
    #include 从另一个文件插入特定的标头
    #undef 未定义预处理器宏
    #ifdef 如果定义了此宏,则返回true
    #ifndef 如果未定义此宏,则返回true
    #if 测试编译时间条件是否为true
    #else #if的替代块
    #elif 在一条语句中#else一个#if
    #endif 有条件地结束预处理器
    #error 在stderr上显示错误消息
    #pragma 使用标准化方法向编译器发出特殊命令
  • 预处理器示例

    分析以下示例以了解各种指令。
    
    #define MAX_ARRAY_LENGTH 20
    
    该指令告诉OCPP将MAX_ARRAY_LENGTH的实例替换为20。对常量使用#define以提高可读性。
    
    #import <Foundation/Foundation.h>
    #include "myheader.h"
    
    这些指令告诉OCPP从Foundation Framework获取Foundation.h并将文本添加到当前源文件中。下一行告诉OCPP 从本地目录获取myheader.h并将内容添加到当前源文件中。
    
    #undef  FILE_SIZE
    #define FILE_SIZE 42
    
    这告诉OCPP取消定义现有的FILE_SIZE并将其定义为42。
    
    #ifndef MESSAGE
       #define MESSAGE "You wish!"
    #endif
    
    这告诉OCPP仅在尚未定义MESSAGE的情况下定义MESSAGE。
    
    #ifdef DEBUG
       /* Your debugging statements here */
    #endif
    
    如果已定义DEBUG,这将告诉OCPP处理该语句。如果在编译时将-DDEBUG标志传递给gcc编译器,这将很有用。这将定义DEBUG,因此您可以在编译过程中即时打开和关闭调试。
  • 预定义的宏

    ANSI C定义了许多宏。尽管可以在编程中使用每个宏,但是不应直接修改预定义的宏。
    说明
    __DATE__ 当前日期以“MMM DD YYYY”格式文字表示
    __TIME__ 当前时间为字符文字"HH:MM:SS"格式
    __FILE__ 它以字符串文字形式包含当前文件名。
    __LINE__ 它以十进制常量的形式包含当前行号。
    __STDC__ 当编译器符合ANSI标准时定义为1。
    让我们尝试以下示例-
    
    #import <Foundation/Foundation.h>
    
    int main() {
       NSLog(@"File :%s\n", __FILE__ );
       NSLog(@"Date :%s\n", __DATE__ );
       NSLog(@"Time :%s\n", __TIME__ );
       NSLog(@"Line :%d\n", __LINE__ );
       NSLog(@"ANSI :%d\n", __STDC__ );
       
       return 0;
    }
    
    编译并执行上述代码后,将产生以下结果-
    
    2020-08-08 14:29:18.873 test[5680:7372] File :test.m
    2020-08-08 14:29:18.879 test[5680:7372] Date :Aug  8 2020
    2020-08-08 14:29:18.879 test[5680:7372] Time :14:29:16
    2020-08-08 14:29:18.879 test[5680:7372] Line :8
    2020-08-08 14:29:18.879 test[5680:7372] ANSI :1
    
  • 预处理运算符

    Objective-C预处理器提供以下运算符来帮助您创建宏-
    宏延续(\)
    宏通常必须包含在一行中。宏延续运算符用于延续对于一行而言太长的宏。例如-
    
    #define  message_for(a, b)  \
       NSLog(@#a " and " #b ": We love you!\n")
    
    字符串化(#)
    字符串化或数字符号运算符('#')在宏定义中使用时,会将宏参数转换为字符串常量。此运算符只能在具有指定参数或参数列表的宏中使用。例如-
    
    #import <Foundation/Foundation.h>
    
    #define  message_for(a, b)  \
       NSLog(@#a " and " #b ": We love you!\n")
    
    int main(void) {
       message_for(Carole, Debra);
       return 0;
    }
    
    编译并执行上述代码后,将产生以下结果-
    
    2020-08-08 14:33:19.279 test[7320:9192] Carole and Debra: We love you!
    
    令牌粘贴(##)
    宏定义中的令牌粘贴运算符(##)组合了两个参数。它允许将宏定义中的两个单独的标记合并为一个标记。例如-
    
    #import <Foundation/Foundation.h>
    
    #define tokenpaster(n) NSLog (@"token" #n " = %d", token##n)
    
    int main(void) {
       int token34 = 40;
       
       tokenpaster(34);
       return 0;
    }
    
    编译并执行上述代码后,将产生以下结果-
    
    2020-08-08 14:38:22.166 test[12936:5632] token34 = 40
    
    它是这样发生的,因为此示例导致预处理器产生以下实际输出:
    
    NSLog (@"token34 = %d", token34);
    
    此示例显示了将token ## n连接到token34的情况,这里我们同时使用了stringize和token-pasting 。
    define() 运算符
    在常量表达式中使用预处理器定义的运算符,以确定是否使用#define定义了标识符。如果定义了指定的标识符,则该值为true(非零)。如果未定义符号,则该值为false(零)。定义的运算符指定如下-
    
    #import <Foundation/Foundation.h>
    
    #if !defined (MESSAGE)
       #define MESSAGE "You wish!"
    #endif
    
    int main(void) {
       NSLog(@"Here is the message: %s\n", MESSAGE);  
       return 0;
    }
    
    编译并执行上述代码后,将产生以下结果-
    
    2020-08-08 14:45:13.884 test[10460:10808] Here is the message: You wish!
    
  • 参数化的宏

    OCPP的强大功能之一是能够使用参数化宏模拟功能。例如,我们可能有一些代码可以对数字平方,如下所示:
    
    int square(int x) {
       return x * x;
    }
    
    我们可以使用宏重写以下代码,如下所示:
    
    #define square(x) ((x) * (x))
    
    必须先使用#define指令定义带有参数的宏,然后才能使用它们。参数列表用括号括起来,并且必须紧随宏名称之后。宏名称和右括号之间不允许有空格。例如-
    
    #import <Foundation/Foundation.h>
    
    #define MYMAX(x,y) ((x) > (y) ? (x) : (y))
    
    int main(void) {
       NSLog(@"Max between 20 and 10 is %d\n", MYMAX(10, 20));  
       return 0;
    }
    
    编译并执行上述代码后,将产生以下结果-
    
    2020-08-08 14:59:23.923 test[9200:2856] Max between 20 and 10 is 20