[Objective-C语言教程]预处理器(18)

Objective-C预处理器不是编译器的一部分,而是编译过程中的一个单独步骤。 简单来说,Objective-C预处理器只是一个文本替换工具,它指示编译器在实际编译之前进行必要的预处理。 我们将Objective-C预处理器称为OCPP

所有预处理器命令都以井号(#)开头。它必须是第一个字符(前面不能有空格),并且为了便于阅读,预处理器指令应该从第一列开始。 以下部分列出了所有重要的预处理程序指令 -

编号指令描述
1 #define 替换预处理器宏
2 #include 从另一个文件插入特定标头
3 #undef 未定义的预处理器宏
4 #ifdef 如果定义了此宏,则返回true
5 #ifndef 如果未定义此宏,则返回true
6 #if 测试编译时条件是否为true
7 #else #if的替代方案
8 #elif #else#if 中的一个语句
9 #endif 结束预处理器条件
10 #error stderr上打印错误消息
11 #pragma 使用标准化方法向编译器发出特殊命令

1. 预处理器示例

分析以下示例以了解各种宏的指令。

#define MAX_ARRAY_LENGTH 20

该指令告诉OCPP20替换MAX_ARRAY_LENGTH宏标识。使用#define定义常量来提高可读性。

1 #import <Foundation/Foundation.h>
2 #include "myheader.h"

这些指令告诉OCPP 从Foundation Framework获取foundation.h,并将文本添加到当前源文件中。 下一行告诉OCPP 从本地目录获取myheader.h并将内容添加到当前源文件。

1 #undef  FILE_SIZE
2 #define FILE_SIZE 42

它告诉OCPP 取消定义现有的FILE_SIZE,并将FILE_SIZE定义为42

1 #ifndef MESSAGE
2    #define MESSAGE "You wish!"
3 #endif

它告诉OCPP仅在尚未定义MESSAGE宏时才定义MESSAGE

1 #ifdef DEBUG
2    /* Your debugging statements here */
3 #endif

它告诉OCPP如果定义了DEBUG,则执行包含语句的过程。 如果在编译时将- DDEBUG标志传递给gcc编译器,这将非常有用。 它将定义DEBUG,因此可以在编译期间动态打开和关闭调试。

2. 预定义的宏

ANSI C定义了许多宏。虽然每个都可用于编程,但不应直接修改预定义的宏。

编号描述
1 __DATE__ 当前日期为“MMM DD YYYY”格式的字符文字
2 __TIME__ 当前时间作为“HH:MM:SS”格式的字符文字
3 __FILE__ 它包含当前文件名作为字符串文字。
4 __LINE__ 它包含当前行号作为十进制常量。
5 __STDC__ 当编译器符合ANSI标准时,定义为1

试试下面的例子代码 -

 1 #import <Foundation/Foundation.h>
 2 
 3 int main() {
 4    NSLog(@"File :%s
", __FILE__ );
 5    NSLog(@"Date :%s
", __DATE__ );
 6    NSLog(@"Time :%s
", __TIME__ );
 7    NSLog(@"Line :%d
", __LINE__ );
 8    NSLog(@"ANSI :%d
", __STDC__ );
 9 
10    return 0;
11 }

当编译并执行文件main.m 中的上述代码时,它会产生以下结果 -

1 2018-11-15 08:44:54.041 main[50640] File :main.m
2 2018-11-15 08:44:54.042 main[50640] Date :Nov 15 2018
3 2018-11-15 08:44:54.042 main[50640] Time :08:44:52
4 2018-11-15 08:44:54.042 main[50640] Line :7
5 2018-11-15 08:44:54.043 main[50640] ANSI :1

3. 预处理器运算符

Objective-C预处理器提供以下运算符来创建宏 -

3.1. 宏延续()

宏通常必须包含在一行中。宏延续运算符用于继续对于单行来说太长的宏。 例如 -

1 #define  message_for(a, b)  
2    NSLog(@#a " and " #b ": We love you!
")

3.2. 字符串化(#)

字符串化或数字符号运算符(#)在宏定义中使用时,将宏参数转换为字符串常量。 此运算符只能在具有指定参数或参数列表的宏中使用。 例如 -

1 #import <Foundation/Foundation.h>
2 
3 #define  message_for(a, b)  
4    NSLog(@#a " and " #b ": We love you!
")
5 
6 int main(void) {
7    message_for(Carole, Debra);
8    return 0;
9 }

执行上面示例代码,得到以下结果:

1 2018-11-15 08:56:38.088 main[98681] Carole and Debra: We love you!

3.3. 令牌粘贴(##)

宏定义中的令牌粘贴运算符(##)组合了两个参数。 它允许将宏定义中的两个单独的标记连接到一个标记中。 例如 -

 1 #import <Foundation/Foundation.h>
 2 
 3 #define tokenpaster(n) NSLog (@"token" #n " = %d", token##n)
 4 
 5 int main(void) {
 6    int token34 = 40;
 7 
 8    tokenpaster(34);
 9    return 0;
10 }

执行上面示例代码,得到以下结果:

2018-11-15 08:58:04.872 main[138839] token34 = 40

它是如何发生的,因为这个例子导致预处理器的以下实际输出 -

NSLog (@"token34 = %d", token34);

此示例显示令牌##ntoken34的串联,这里使用了stringizetoken-pasting

3.4. defined()运算符

预处理器定义的运算符用于常量表达式,以确定是否使用#define定义标识符。如果定义了指定的标识符,则该值为true(非零)。 如果未定义符号,则值为false(零)。 定义的运算符指定如下 -

 1 #import <Foundation/Foundation.h>
 2 
 3 #if !defined (MESSAGE)
 4    #define MESSAGE "You wish!"
 5 #endif
 6 
 7 int main(void) {
 8    NSLog(@"Here is the message: %s
", MESSAGE);  
 9    return 0;
10 }

执行上面示例代码,得到以下结果:

1 2018-11-15 09:04:30.790 main[31654] Here is the message: You wish!

4. 参数化宏

OCPP的一个强大功能是使用参数化宏模拟函数的能力。 例如,可能需要一些代码来对数字进行平方,如下所示 -

1 int square(int x) {
2    return x * x;
3 }

可以使用宏重写上面的代码,如下所示 -

#define square(x) ((x) * (x))

必须先使用#define指令定义带参数的宏,然后才能使用它们。 参数列表括在括号中,并且必须紧跟宏名称。 宏名称和左括号之间不允许有空格。 例如 -

1 #import <Foundation/Foundation.h>
2 
3 #define MAX(x,y) ((x) > (y) ? (x) : (y))
4 
5 int main(void) {
6    NSLog(@"Max between 20 and 10 is %d
", MAX(10, 20));  
7    return 0;
8 }

执行上面示例代码,得到以下结果:

2018-11-15 09:08:15.586 main[64146] Max between 20 and 10 is 20
原文地址:https://www.cnblogs.com/strengthen/p/10571484.html