Objective-C 预处理器 - 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