您好,欢迎访问三七文档
当前位置:首页 > 行业资料 > 国内外标准规范 > 不带参数的宏定义rtse
不带参数的宏定义:宏定义又称为宏代换、宏替换,简称“宏”。格式:#define标识符字符串其中的标识符就是所谓的符号常量,也称为“宏名”。预处理(预编译)工作也叫做宏展开:将宏名替换为字符串。掌握宏概念的关键是“换”。一切以换为前提、做任何事情之前先要换,准确理解之前就要“换”。即在对相关命令或语句的含义和功能作具体分析之前就要换:例:#definePI3.1415926把程序中出现的PI全部换成3.1415926说明:(1)宏名一般用大写(2)使用宏可提高程序的通用性和易读性,减少不一致性,减少输入错误和便于修改。例如:数组大小常用宏定义(3)预处理是在编译之前的处理,而编译工作的任务之一就是语法检查,预处理不做语法检查。(4)宏定义末尾不加分号;(5)宏定义写在函数的花括号外边,作用域为其后的程序,通常在文件的最开头。(6)可以用#undef命令终止宏定义的作用域(7)宏定义可以嵌套(8)字符串中永远不包含宏(9)宏定义不分配内存,变量定义分配内存。2.带参数的宏:除了一般的字符串替换,还要做参数代换格式:#define宏名(参数表)字符串例如:#defineS(a,b)a*barea=S(3,2);第一步被换为area=a*b;,第二步被换为area=3*2;类似于函数调用,有一个哑实结合的过程:(1)实参如果是表达式容易出问题#defineS(r)r*rarea=S(a+b);第一步换为area=r*r;,第二步被换为area=a+b*a+b;正确的宏定义是#defineS(r)(r)*(r)(2)宏名和参数的括号间不能有空格(3)宏替换只作替换,不做计算,不做表达式求解(4)函数调用在编译后程序运行时进行,并且分配内存。宏替换在编译前进行,不分配内存(5)宏不存在类型,也没有类型转换。(6)函数只有一个返回值,利用宏则可以设法得到多个值(7)宏展开使源程序变长,函数调用不会(8)宏展开不占运行时间,只占编译时间,函数调用占运行时间(分配内存、保留现场、值传递、返回值)1、尽量用const和inline而不用#define这个条款最好称为:“尽量用编译器而不用预处理”,因为#define经常被认为好象不是语言本身的一部分。这是问题之一。2、再看下面的语句:#defineASPECT_RATIO1.653编译器会永远也看不到ASPECT_RATIO这个符号名,因为在源码进入编译器之前,它会被预处理程序去掉,于是ASPECT_RATIO不会加入到符号列表中。如果涉及到这个常量的代码在编译时报错,就会很令人费解,因为报错信息指的是1.653,而不是ASPECT_RATIO。如果ASPECT_RATIO不是在你自己写的头文件中定义的,就会奇怪1.653是从哪里来的,甚至会花时间跟踪下去。这个问题也会出现在符号调试器中,因为同样所写的符号名不会出现在符号列表中。解决这个问题的方案很简单:不用预处理宏,定义一个常量:constdoubleASPECT_RATIO=1.653;这种方法很有效。但有两个特殊情况要注意。首先,定义指针常量时会有点不同。因为常量定义一般是放在头文件中(许多源文件会包含它),除了指针所指的类型要定义成const外,重要的是指针也经常要定义成const。例如,要在头文件中定义一个基于char*的字符串常量,要写两次const:constchar*constauthorName=ScottMeyers;可以用const来定义常量,也可以用#define来定义常量。但是前者比后者有更多的优点:(1)const常量有数据类型,而宏常量没有数据类型。编译器可以对前者进行类型安全检查。而对后者只进行字符替换,没有类型安全检查,并且在字符替换可能会产生意料不到的错误(边际效应)。(2)有些集成化的调试工具可以对const常量进行调试,但是不能对宏常量进行调试。。2.实现机制宏是预处理命令,即在预编译阶段进行字节替换。const常量是变量,在执行时const定义的只读变量在程序运行过程中只有一份拷贝(因为它是全局的只读变量,存放在静态存储区的只读数据区。当你声明该量为常量,即告诉程序和编译器,你不希望此量被修改。程序的实现,为了保护常量,特将常量都放在受保护的静态存储区内。凡是试图修改这个区域内的值,都将被视为非法,并报错。这不能理解为凡是字符串都是放在静态存储区域的。这个跟数据类型没有关系,而是这个量是变量还是常量的问题。例如,一个字符串变量就是可以被修改的。这种静态存储区域的保护机制是由编译器实现的,而非存储该值的内存的电器属性。换言之,实质上内存永远都可以被用户随意修改,只是编译器给用户的代码注入了一些自己的保护代码,通过软件手段将这段内存软保护起来。这种保护在汇编级别可以轻松突破,其保护也就无效了。)。3.用法区别define宏定义和const常变量区别:1.define是宏定义,程序在预处理阶段将用define定义的内容进行了替换。因此程序运行时,常量表中并没有用define定义的常量,系统不为它分配内存。const定义的常量,在程序运行时在常量表中,系统为它分配内存。2.define定义的常量,预处理时只是直接进行了替换。所以编译时不能进行数据类型检验。const定义的常量,在编译时进行严格的类型检验,可以避免出错。3.define定义表达式时要注意“边缘效应”,例如如下定义:#defineN2+3//我们预想的N值是5,我们这样使用N,inta=N/2;//我们预想的a的值是2.5,可实际上a的值是3.5原因在于在预处理阶段,编译器将a=N/2处理成了a=2+3/2;这就是宏定义的字符串替换的“边缘效应”因此要如下定义:#defineN(2+3)。const定义表达式没有上述问题。const定义的常量叫做常变量原因有二:const定义常量像变量一样检查类型;const可以在任何地方定义常量,编译器对它的处理过程与变量相似,只是分配内存的地方不同。1.Objective-C中声明常量使用关键字const。如:constdoublePI=3.1514;2.Objective-C中变量可以分为成员变量、局部变量和全局变量(用的很少,尽量不要用)。//————————------------常量—————————————————//方法一:#definekDetailKey@“detailtext”#defineDOWNLOAD_TIMEOUT60.0#definedegresssToRadian(x)(M_PT*(X)/180.0)这种方法直接使用#define定义函数、字符串和数字,和普通的C/C++一样,唯一的区别是字符串需要在前面加上“@”符号。方法二:typedefenum{kTagLanguageView=100,kTagSeriesView,kTagSeriesDetailView,kTagThumbView,kTagVideoView,kTagFullPhotoView,}TagSystemViews;使用枚举定义常量,在这里kTagSeriesView等于101,在程序中直接使用kTagSeriesView来表示这个常量,这和C/C++一样。方法三:在.m或者.mm文件中使用静态常量声明,和C/C++使用方法一样,例如:staticNSString*BlockColorAlphaComponentKey=@blockColorAlphaComponent”;//————————------------变量—————————————————//1.为了强制一个对象隐藏其数据,编译器限制实例变量范围以限制其在程序中的可见性。但是为了提供灵活性,苹果也让开发者显示设置范围(四选一)。2.四种编译指令如下:@private实例变量只能被声明它的类访问。@protected实例变量能被声明它的类和子类,所有没有显示指定范围的实例变量都是@protected。@public实例变量可以在任何地方被访问。@packge使用modern运行时,一个@package实例变量在实现这个类的可执行文件镜像中实际上是@public的,但是在外面就是@private。OC中的@package与C语言中的变量和函数的private_extern类似。任何在实现类的镜像之外想使用这个实例变量都会引发linkerror。这个类型最常用于框架类的实例变量,使用@private太限制,使用@protected或者@public又太开放。//——————————————属性—————————————————//属性:@property:@property只不过是给编译器看的一种指令,它可以编译之后自动为你生成相应的getter和setter方法。1.公共属性表示你打算如何使用这一类的对象。2.属性声明是一个指令,它告诉编译器如何为变量生成存取方法。(添加属性声明后,你将了解到有关存取方法的信息)3.id类型是一个通用类型,OC使用id表示任意类型的对象,它可以作为一个占位符表示这是一个不确定的类型的对象或者引用。因此,所有的对象都可以用id来表示。4.编译器指令@property可以为一个类声明属性,这是一个偷懒的好方法,用@property声明属性相当于同时声明并实现了对应的实例变量的访问器方法。当然,也可以通过指定属性的特性(Attribute)类控制自动生成的访问器方法的行为。5.OC里的实例变量默认都是私有的。私有变量只在类自身和子类的实例方法里可见。6.iOSOC声明变量在@interface括号中和使用@proper的区别:方式一:直接在@interface中的大括号中声明。@interfaceMyTest:NSObject{NSString*mystr;}方式二:直接用@property声明@interfaceMyTest:NSObject@property(strong,nonatomic)NSString*mystr;随后在.m文件中@synthesizemystr=_myStr;(也可以在.m文件中不加@synthesize)区别:方式一声明的成员变量是只能在自己类内部使用,而不能在类的外部使用(就是通过类名.点的方式显示不出来。)。方式二可以在类的外部访问,也可以在类的内部通过下划线+变量名或者self.变量名的方式访问。苹果开发模板推荐的是方式二。7.OC是C的严格父集,C能做的事情OC中都能做。属性实际上一个setter方法和一个getter方法,所有对实例变量的访问都是如此,通过setter方法设置值,通过getter方法获取值你没有必要去优化没有必要优化的东西,你要优化的是很花时间的东西,而访问实例变量不会花太多时间。8..h是共有的API.m是私有的API以及你所有的实现。所有指针要么是强的,要么是弱的,因为OC需要知道怎样处理内存和堆。强表示保持这个的存储,在堆中,保持这个所指的东西7.plist:属性配置文件,基于XML格式,也扮演了一部分定义UI的角色,Xcode在编译的时候会读取里面的配置信息。8.类的声明提供了这个类和程序员之间的接口,类的声明即接口,其实现代码才是真正执行实际任务的地方。类的声明以@interface指令开始,以@end指令结束。9.蓝色的竖线:它是UI控件和屏幕边框的距离参考线以及对齐参考线,用于设置控件在不同大小的屏幕上的位置。13.属性使用点语法,其他情况使用方括号标记语法。***********************************copy:1.简单复制只能实现浅拷贝:指针赋值,使每个指针指向相同的一块内存空间,操作不安全。2.在iOS中可以这样实现:Foundation类已经遵守了NSCopying和NSMutableCopying协议,即实现了copy和mutableCopy方法,因此Foundation对象可以使用这些方法创建对象的副本或可变副本。**************************为属性声明自定义特性1.访问器
本文标题:不带参数的宏定义rtse
链接地址:https://www.777doc.com/doc-2785897 .html