博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
OC基础9:预处理程序
阅读量:4879 次
发布时间:2019-06-11

本文共 2507 字,大约阅读时间需要 8 分钟。

  "OC基础"这个分类的文章是我在自学Stephen G.Kochan的《Objective-C程序设计第6版》过程中的笔记。

 

1、  关于#define语句:

(1)、#define语句的用途就是给某个符号名称指定一个程序要用到的常量,比如:

#define TRUE 1

这个语句的意思就是把TRUE指定为1,那么后续的程序中如果需要用到1来做判断或者计算,就可以直接使用TRUE这个符号名称了;

   (2)、预定义名称不是变量,所以不能在程序过程中给它赋值,不能改变它的值;

   (3)、注意#define语句没有用到等号,也不需要分号结尾,如果结尾加上分号的话,那么这个常量的值就会变成你想要的值和一个分号的合并了,即是这个分号也会被和值同时替换到这个预定义名称中;

   (4)、#define语句一般写在程序开始的地方,#import和include语句后面,但是其实它可以出现在程序的任何位置,只要出现在程序引用它的位置之前即可;

   (5)、预定义名称和变量不同,它没有局部作用域这个概念,你可以在程序中任何位置使用你定义过的预定义名称。一般把它放在头文件中,以便在多个源文件中使用它们;

   (6)、使用预定义名称来代替常量值,这样增加了程序的可读性,能清晰地看到某个常量的含义以及它的用途。同时如果使用了这种方法定义常量,然后在程序中发现这个常量出错了,那么你只需要修改#define语句,而不需要整个程序去查找这个常量出现的地方并一个一个修改;

   (7)、一般来说预定义名称有两种命名习惯:一种是全部字母都大写,比如(1)的例子,一种是k开头,比如(1)的预定义名称也可以写作kTrue。

 

2、其实编译器在处理预定义名称的时候,所做的仅仅是简单的查找替换,编译过程中把所有的预定义名称替换成所定义的值;

 

3、在#define语句中还可以出现表达式,比如这个例子是合法的:

   #define TWO_PI 2.0*3.1415926

   也可以出现关系运算符,比如这个例子也是合法的:

   #define AND &

  

4、预定义的值本身可以引用另一个预定义的值,比如:

   #define PI 3.1415926

   #define TWO_PI 2.0*PI

   这种情况是合法的,设置把这个两个语句的顺序颠倒过来,也是合法的。

 

5、如果预定义的名称或者值过长,甚至需要换行写,那么上一行的最后一个字符必须是反斜杠,如下例:

   #define XXX ( 2.0 * 5.0 + 31.0 * 7.0 ) \

   * 56.0

   这个表达式相当于( 2.0 * 5.0 + 31.0 * 7.0 ) * 56.0,注意是可以有空格的。

 

6、关于宏:

   (1)、可以让预定义名称本身带着一个或多个参数,在编译的时候,编译器会自动把参数替换到预定义值的对应位置去。这种预定义成为宏。如下例子:

   #define XXX(y) y * 2.0 + y / 5.0

   这个预定义允许你在代码中写出n=XXX(5); 这样的语句;

   (2)、宏和方法不同,宏的参数是没有类型的,仅仅只是执行字面意义上的替换。同时需要注意,在预定义名称和参数列表的括号之间不允许有空格

   (3)、在定义宏时,参数列表内的每个单独的参数都要打上括号,因为宏只是执行字面意义上的替换,不打括号会有可能出错。如果定义一个宏如下:

       #define SQUARE(x) x * x

       那么当出现n=SQUARE(y+1)时,这个等式会被替换称n=y+1*y+1,就与本来想求的值不同了。所以这个预定义应该写为:

       #define SQUARE(x) ((x) * (x))

       全部用括号括起来最保险,因为你有可能会使用SQUARE(x)去和其他数值运算;

   (4)、甚至在宏的预定义值中可以调用方法,假设Fraction类有一个初始化的设值方法initWith:over:,那么可以有以下宏定义:

       #define MAKE_FRAC(x,y) ([[Fraction alloc] initWith:x over:y])

   (5)、宏中允许出现判断语句,比如:

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

   (6)、宏中允许出现关系运算符,比如:

       #define IS_LOWER_CASE(x) ((x)>=’a’ && (x)<=’z’)

   (7)、甚至可以在宏中进行字符从小写到大写的转换,如下例子:

       #define TO_UPPER(x) (IS_LOWER_CASE(x)? (x)-‘a’+’A’: (x))

 

7、可以把所有要用到的预处理定义收集到单独一个h文件中,然后在程序中使用#import把它引入进来。一般使用双引号引入。

 

8、使用双引号引入文件,系统会在包括当前目录在内的多个目录查找引入文件;把文件名放在尖括号里面,会导致系统只在“特殊”的系统文件目录中查找包含文件。

 

9、关于几个条件编译语句:

   (1)、有时候系统需要使用到硬件的类型来作为参数,比如某个页面在iPad和iPhone上的显示可能就会不同,需要显示不同尺寸的图片,那么此时就需要判断系统的某些参数。

       假设在一个iPad程序中已做了以下定义:

       #define IPAD 1

       那么可以使用条件编译语句进行如下判断来选择要显示那张图片:

       #ifdef IPAD

       # define kImageFile @”xxxIPad.png”

       #else

       #  define kImageFile @”xxx.png”

       #endif

       这里就使用了#ifdef、#else和#endif这三个条件编译语句进行了判断;

   (2)、同时可以注意到(1)中,#define语句在井号和define之间可以出现空格;

   (3)、另外还有#if和#elif两种语句,if语句用来判断常量表达式是否为0;

 

10、最后还有一个#undef语句,这个语句可以将一些已经定义过的名称消除掉,恢复到未定义的状态;

 

转载于:https://www.cnblogs.com/shayneyeorg/p/4638771.html

你可能感兴趣的文章
开环增益对负反馈放大电路的影响
查看>>
MySQL-ERROR 2003
查看>>
SQL Server2012-SSIS的包管理和部署
查看>>
JavaScript内置对象
查看>>
如何把js的循环写成异步的
查看>>
ER图是啥?
查看>>
too many include files depth = 1024错误原因
查看>>
HTTP协议详解(三)
查看>>
Android零基础入门第84节:引入Fragment原来是这么回事
查看>>
解析SQL Server之任务调度
查看>>
参考资料地址
查看>>
08.路由规则中定义参数
查看>>
Pandas截取列部分字符,并据此修改另一列的数据
查看>>
java.lang.IllegalArgumentException
查看>>
【Spark】编程实战之模拟SparkRPC原理实现自定义RPC
查看>>
接口实现观察者模式
查看>>
四则运算完结篇
查看>>
Objective-C中的类目,延展,协议
查看>>
Python标准模块--Iterators和Generators
查看>>
Introduction Sockets to Programming in C using TCP/IP
查看>>