📜  Objective-C预处理器

📅  最后修改于: 2020-11-03 15:58:04             🧑  作者: Mango


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

所有预处理器命令均以井号(#)开头。它必须是第一个非空白字符,并且为了便于阅读,预处理器指令应在第一列中开始。以下部分列出了所有重要的预处理器指令-

Sr.No. Directive & Description
1

#define

Substitutes a preprocessor macro

2

#include

Inserts a particular header from another file

3

#undef

Undefines a preprocessor macro

4

#ifdef

Returns true if this macro is defined

5

#ifndef

Returns true if this macro is not defined

6

#if

Tests if a compile time condition is true

7

#else

The alternative for #if

8

#elif

#else an #if in one statement

9

#endif

Ends preprocessor conditional

10

#error

Prints error message on stderr

11

#pragma

Issues special commands to the compiler using a standardized method

预处理器示例

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

#define MAX_ARRAY_LENGTH 20

该指令告诉OCPP将MAX_ARRAY_LENGTH的实例替换为20。对常量使用#define以提高可读性。

#import 
#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定义了许多宏。尽管您可以在编程中使用每个宏,但是不应直接修改预定义的宏。

Sr.No. Macro & Description
1

__DATE__

The current date as a character literal in “MMM DD YYYY” format

2

__TIME__

The current time as a character literal in “HH:MM:SS” format

3

__FILE__

This contains the current filename as a string literal.

4

__LINE__

This contains the current line number as a decimal constant.

5

__STDC__

Defined as 1 when the compiler complies with the ANSI standard.

让我们尝试以下示例-

#import 

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;
}

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

2013-09-14 04:46:14.859 demo[20683] File :main.m
2013-09-14 04:46:14.859 demo[20683] Date :Sep 14 2013
2013-09-14 04:46:14.859 demo[20683] Time :04:46:14
2013-09-14 04:46:14.859 demo[20683] Line :8
2013-09-14 04:46:14.859 demo[20683] ANSI :1

预处理运算符

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

宏延续(\)

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

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

字符串化(#)

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

#import 

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

int main(void) {
   message_for(Carole, Debra);
   return 0;
}

编译并执行上述代码后,将产生以下结果-

2013-09-14 05:46:14.859 demo[20683] Carole and Debra: We love you!

令牌粘贴(##)

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

#import 

#define tokenpaster(n) NSLog (@"token" #n " = %d", token##n)

int main(void) {
   int token34 = 40;
   
   tokenpaster(34);
   return 0;
}

编译并执行上述代码后,将产生以下结果-

2013-09-14 05:48:14.859 demo[20683] token34 = 40

怎么发生的,因为此示例导致预处理器的以下实际输出-

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

此示例显示了将token ## n连接到token34的情况,这里我们同时使用了stringizetoken- pasting。

define()运算符

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

#import 

#if !defined (MESSAGE)
   #define MESSAGE "You wish!"
#endif

int main(void) {
   NSLog(@"Here is the message: %s\n", MESSAGE);  
   return 0;
}

编译并执行上述代码后,将产生以下结果-

2013-09-14 05:48:19.859 demo[20683] Here is the message: You wish!

参数化的巨集

OCPP的强大功能之一是能够使用参数化宏模拟功能。例如,我们可能有一些代码可以对数字平方,如下所示:

int square(int x) {
   return x * x;
}

我们可以使用宏重写以下代码,如下所示:

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

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

#import 

#define MAX(x,y) ((x) > (y) ? (x) : (y))

int main(void) {
   NSLog(@"Max between 20 and 10 is %d\n", MAX(10, 20));  
   return 0;
}

编译并执行上述代码后,将产生以下结果-

2013-09-14 05:52:15.859 demo[20683] Max between 20 and 10 is 20