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。使用#定义常数,以增加可读性。
#import <Foundation/Foundation.h> #include "myheader.h"
这些的指令告诉OCPP得到 foundation.h 基础框架和文本添加到当前源文件。下一行告诉 OCPP 从本地目录得到 myheader.h 的内容添加到当前源文件。
#undef FILE_SIZE #define FILE_SIZE 42
告诉OCPP 取消对现有 FILE_SIZE 的定义,并把它定义为42 。
#ifndef MESSAGE #define MESSAGE "You wish!" #endif
这告诉OCPP定义消息,如果消息没有被定义。
#ifdef DEBUG /* Your debugging statements here */ #endif
这告诉OCPP如果DEBUG被定义语句随附过程。如果传递 DDEBUG标志,gcc编译器在编译时,这是非常有用的。这将定义DEBUG,所以可以在编译过程中打开调试和关闭。
预定义宏
ANSI C定义了一些宏。虽然每一个都是供编程使用,预定义宏不应该被直接修改。
Macro | 描述 |
---|---|
__DATE__ | The current date as a character literal in "MMM DD YYYY" format |
__TIME__ | The current time as a character literal in "HH:MM:SS" format |
__FILE__ | This contains the current filename as a string literal. |
__LINE__ | This contains the current line number as a decimal constant. |
__STDC__ | Defined as 1 when the compiler complies with the ANSI standard. |
让我们试试下面的例子:
#import <Foundation/Foundation.h> int main() { NSLog(@"File :%s ", __FILE__ ); NSLog(@"Date :%s ", __DATE__ ); NSLog(@"Time :%s ", __TIME__ ); NSLog(@"Line :%d ", __LINE__ ); NSLog(@"ANSI :%d ", __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! ")
Stringize (#)
stringize或数字符号运算符('#'),在宏定义内使用时,一个宏参数转换成一个字符串常量。此操作只可用于在宏具有指定参数或参数列表。例如:
#import <Foundation/Foundation.h> #define message_for(a, b) NSLog(@#a " and " #b ": We love you! ") 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 <Foundation/Foundation.h> #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);
这个例子显示了串联令牌#n为进token34,这里我们使用stringize和标记粘贴。
defined() 运算符
预处理器定义的常量表达式运算符用于确定是否使用#define定义一个标识符。如果指定的标识符被定义,该值是真(非零)。如果符号没有定义,这个值是false(零)。定义的运算符规定如下:
#import <Foundation/Foundation.h> #if !defined (MESSAGE) #define MESSAGE "You wish!" #endif int main(void) { NSLog(@"Here is the message: %s ", 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 <Foundation/Foundation.h> #define MAX(x,y) ((x) > (y) ? (x) : (y)) int main(void) { NSLog(@"Max between 20 and 10 is %d ", MAX(10, 20)); return 0; }
让我们编译和运行上面的程序,这将产生以下结果:
2013-09-14 05:52:15.859 demo[20683] Max between 20 and 10 is 20