【IOS 开发学习总结-OC-7.4】objective-c与c语言的预处理

来源:互联网 发布:公司seo是什么意思 编辑:程序博客网 时间:2024/05/02 11:14

在编译器对 C或者 objective-c 进行编译前,编译器会对这些预处理命令进行处理,然后将这些预处理的结果与源程序一起编译。

预处理命令的2个特征:
1.都必须以#开头
2.通常位于程序开头部分。

使用#define及#undef 执行宏定义

这里#define的作用是:为字符串起一个名字。可以使用更有意义的名字代替原来的字符串。为编程提供便利。
示例:#define PI 3.14159,通常来说,宏名称通常会使用所有字母的大写形式。

宏定义注意点:

  • 宏定义不是C 语句。无需用分号结束,也不要使用=进行赋值。
  • 宏定义不是变量。不要对宏名称进行赋值。
  • 编译器处理宏定义,只是进行”查找,替换”,要保证宏定义是正确的。
    执行宏定义后,该宏的作用 域为定义该宏开始,直到该源代码结束,如果想提前结束宏定义,可以使用语句:#undef 宏名称
    示例代码:
#import <Foundation/Foundation.h>// 定义PI代替3.1415926#define PI 3.1415926int main(int argc , char * argv[]){    @autoreleasepool{        NSLog(@"请输入圆的半径:");        double radius;        scanf("%lg" , &radius);        // 使用PI        NSLog(@"圆周长:%g" , PI * 2 * radius);        NSLog(@"圆面积:%g" , PI * radius * radius);    }}

开发技巧:
实际项目开发中,常把一些未来可能需要修改的值定义成宏,这样可以避免批量更改代码中的值。


宏定义还可以引用另一个已有的宏,从而形成嵌套替换的宏。示例代码:

#import <Foundation/Foundation.h>// 定义PI代替3.1415926#define PI 3.1415926// 直接使用前面已有的PI来定义新的宏#define GIRTH(r) (PI * 2 * (r))// 直接使用前面已有的PI来定义新的宏#define AREA(r) (PI * (r) * (r))int main(int argc , char * argv[]){    @autoreleasepool{        NSLog(@"请输入圆的半径:");        double radius;        scanf("%lg" , &radius);        // 使用宏执行计算        NSLog(@"圆周长:%g" , GIRTH(radius));        NSLog(@"圆面积:%g" , AREA(radius));    }}

带参数的宏定义

除了定义简单的宏以外,可以在宏定义中使用参数,这样定义的宏更灵活。
语法格式为:#define 宏名称(参数列表) 字符串

示例代码:

#import <Foundation/Foundation.h>// 定义PI代替3.1415926#define PI 3.1415926// 直接使用前面已有的PI来定义新的宏#define GIRTH(r) (PI * 2 * (r))// 直接使用前面已有的PI来定义新的宏#define AREA(r) (PI * (r) * (r))int main(int argc , char * argv[]){    @autoreleasepool{        NSLog(@"请输入圆的半径:");        double radius;        scanf("%lg" , &radius);        // 使用宏执行计算        NSLog(@"圆周长:%g" , GIRTH(radius));        NSLog(@"圆面积:%g" , AREA(radius));    }}

注意:因为宏定义只是执行简单查找和替换,当传入的参数是个表达式的时候,常会出现一些我们不希望出现的错误。所以,为了编译器能正确处理宏定义,建议将宏定义中的参数用圆括号括起来。如果整个宏定义返回的是数值,可再将整个宏定义的字符串用圆括号括起来。就像上面的代码那样做的。


使用#ifdef,#ifndef,#else,#endif 执行条件编译

有时候需要选择性编译——比如对于特定的设备,只编译该设备相关的代码,就可以借助条件编译来完成。
语法格式1:

#ifdef  宏名称//任意语句#endif

如果定义了指定的宏,则执行#ifdef 和#endif之间的语句。
语法格式2:

#ifdef  宏名称    //任意语句#else     //任意语句#endif

如果定义了指定的宏,则执行#ifdef 和#else之间的语句,否则执行#else和#endif之间的语句。

与此类似的一组,是#ifndef, # else,#endif 组成的。也跟上面是一个形式,只是把#ifdef换成了#ifndef。#ifndef的意思是如果没有定义指定的宏。
语法格式1:

#ifndef  宏名称//任意语句#endif

如果没有定义指定的宏,则执行#ifndef 和#endif之间的语句。
语法格式2:

#ifndef  宏名称    //任意语句#else     //任意语句#endif

如果没有定义指定的宏,则执行#ifndef 和#else之间的语句,否则执行#else和#endif之间的语句。
示例代码:

// 定义iPad宏#define iPadint main(int argc , char * argv[]){    @autoreleasepool{        #ifdef iPad            NSLog(@"这是iPad平板");            NSLog(@"下面执行关于iPad的代码");        #else            NSLog(@"这是iPhone手机");            NSLog(@"下面执行关于iPhone的代码");        #endif    }}

通过上面代码中的条件编译语句,源程序可以不做任何修改就可以自动适应不同的设备。

宏定义用法@利用宏定义控制调试信息是否输出

利用宏定义控制调试信息是否输出。示例代码:

#import <Foundation/Foundation.h>int main(int argc , char * argv[]){    @autoreleasepool{        for(int i = 0 ; i < 10 ; i++)        {            #ifdef DEBUG                NSLog(@"调试输出:i的值为,%d" , i);            #endif        }    }}

使用#if,#elif,#else,#endif 提供了更通用的条件编译

可以对表达式进行判断,根据表达式的值决定是否要编译指定的语句。
语法格式:

#if  表达式//任意语句#elif  表达式...// 可以有零到多个#elif 语句#else//任意语句#endif

示例代码:

#import <Foundation/Foundation.h>#define AGE 25int main(int argc , char * argv[]){    @autoreleasepool{        #if AGE > 60            NSLog(@"老年人");        #elif AGE > 40            NSLog(@"中年人");        #elif AGE > 20            NSLog(@"青年人");        #else            NSLog(@"少年人");        #endif                                  }}

有了流程控制语句,条件编译指令还有什么卵用?

条件编译是在编译器编译之前进行的预处理。使用条件编译指令后,不符合条件的程序语句根本不会编译;而普通的分支语句呢,所有的代码都被编译成执行性代码,程序运行时再根据需要决定执行哪些语句。这就意味着普通分支语句,生成的文件更大,而且执行效率更低(需在运行时判断条件)。

#include#import

C语言提供了#include ,objective-c 提供了比#include更好用#import。OC 也能使用#include 但不推荐。

  • # include 指令的作用很简单:将指定的源码插入到当前代码的制定位置。但有个显著的缺点,需要程序员自行判断是否重复导入。但#import可以帮助判断,避免重复导入的问题。
  • #import "Apple"#import <Foundation/Foundation.h>中引号和尖括号的作用是神马?——双引号,告诉预处理程序到当前文件所在路径搜索指定的源文件(也可通过 Xcode 的项目设置来设置预处理的搜索路径);而尖括号<>,告诉预处理程序到相应的系统头文件路径中搜索。
0 0