iOS学习——#define、const、typedef的区别
在iOS开发中经常遇到一些字段和类型的定义,例如配置生产和测试不同环境的参数等,这时候经常用到#define、const以及typedef。那么它们之间有什么区别呢?我们接下来一个一个具体了解下。
一、基本概念
1.1、#define
#define并不是定义全局变量,而是宏定义。也就是说并不是真正意义上的定义变量,而是用来做文本替换。当程序开始运行时,编译器会先将代码中的MAX全部替换为100,然后再进行编译。由此可得,#define并不是在编译过程中进行,而是在预编译阶段进行。
#define MAX 100
宏的常见用法:
- 常见的字符串抽成宏:比喻定义的常用颜色、字体字号等
#define kWaterAlpha 0.04f //水印的透明度 #define kFlowRowSize 30 //流程每次拉去的数量 #define ROW_SIZE 20 //一般刷新每次拉去的数量
- 常见代码抽成宏:比喻单例模板等
//宏定义常用的颜色
#define XRGB(r,g,b) [UIColor colorWithRed:(0x##r)/255.0 green:(0x##g)/255.0 blue:(0x##b)/255.0 alpha:1]
#define kBgColor XRGB(f4, f4, f4)
#define kBlackFontColor XRGB(33, 33, 33)
#define kGrayFontColor XRGB(99, 99, 99)
#define kBlueFontColor XRGB(3d,9a,e8) //宏定义获取当前主界面rootViewController
#define RootVC [UIApplication sharedApplication].delegate.window.rootViewController //宏定义获取当前的界面
#define TopVC ([RootVC isKindOfClass:[UITabBarController class]]?[((UITabBarController *)RootVC).selectedViewController topViewController]:RootVC) //宏定义单例的定义和实现
#define DECLARE_DEFAULT +(instancetype)defaultInstance; #define IMPLEMENT_DEFAULT(C) +(instancetype)defaultInstance{\
static dispatch_once_t onceToken;\
static C *_gInstance;\
dispatch_once(&onceToken, ^{\
_gInstance = [C new];\
});\
return _gInstance;\
}
关于#define的其他用法可以参见后面这篇博文:iOS开发中你真的会用#define么!!!?
1.2、const
关键字const用来定义常量,如果一个常量被const修饰,那么他的值就不能被改变。编译器通常不为普通const常量分配存储空间,而是保存于符号表中,这使得它成为一个编译期间的常量,没有存储与读内存的操作,使得它的效率更高。
常见用法如下:
//全局变量,constString1地址不能修改,constString1值能修改
const NSString *constString1 = @"I am a const NSString * string";
//意义同上,无区别
NSString const *constString2 = @"I am a NSString const * string";
// stringConst 地址能修改,stringConst值不能修改
NSString * const stringConst = @"I am a NSString * const string";
- constString1 跟constString2 无区别
- 左边代表指针本身的类型信息,const表示这个指针指向的这个地址是不可变的
- 右边代表指针指向变量的可变性,即指针存储的地址指向的内存单元所存储的变量的可变性
1.3、typedef
typedef常用于给类型起别名(给已知的类型起别名)。常用于简化复杂类型,变量类型意义化等。typedef是类型替换,语句的一种,结尾必须有;。
//iOS底层源码就是对NSInteger进行了一个别名的设置,其表示的就是long或者int类型。
#if __LP64__ || (TARGET_OS_EMBEDDED && !TARGET_OS_IPHONE) || TARGET_OS_WIN32 || NS_BUILD_32_LIKE_64
typedef long NSInteger;
typedef unsigned long NSUInteger;
#else
typedef int NSInteger;
typedef unsigned int NSUInteger;
#endif
在iOS开发中最常用到的应该就是使用typedef定义枚举和block了,此外还可以用typedef定义函数。关于typedef定义枚举官方API是这样说的
/* NS_ENUM supports the use of one or two arguments. The first argument is always the integer type used for the values of the enum. The second argument is an optional type name for the macro. When specifying a type name, you must precede the macro with 'typedef' like so:
NS_ENUM支持单个或两个参数,第一个参数一般是NSInteger类型来制定枚举的值类型,第二个参数是可选的枚举类型的别名,如果要定义别名,必须使用typedef进行定义,具体格式如下: typedef NS_ENUM(NSInteger, NSComparisonResult) {
...
}; If you do not specify a type name, do not use 'typedef'. For example:
如果不需要使用特定的名称,则不需要使用typedef NS_ENUM(NSInteger) {
...
};
*/
typedef的常见用法如下:
typedef double NSTimeInterval; //给double取别名为NSTimeInterval(变量类型意义化)
typedef NSTimeInterval MyTime; //给NSTimeInterval取别名为MyTime
typedef char * MyString; //给char *取别名为MyString //c语言格式,给Person结构体取别名为MyPerson。使用:MyPerson p = {"jack"};
typedef struct Person {
char *name
}MyPerson; //c语言格式,给Gender枚举取别名为MyGender。使用:MyGender g = Man;
typedef enum Gender {
Man,
Woman
}MyGender; //OC语言格式,给Gender枚举取别名为MyGender。使用:MyGender g = Man;
typedef NS_ENUM(NSInteger, Gender) {
Man,
Woman
}; //给block取别名MyBlock
typedef void(^MyBlock) (int a,int b); //给指向函数的指针取别名MyFunction
typedef int(*MyFunction) (int a,int b);
typedef定义函数的示例:
int add (int a, int b){
return a + b;
} typedef int(*MyMethod) (int a,int b); int main(){
MyMethod m = add;
m(,); //调用函数
return ;
}
二、区别
2.1 #define与const
- 宏在预编译时处理(宏在编译开始之前就会被替换);而const会在编译时被处理
- #define宏没有类型,宏不做任何类型检查,不会报编译错误,只是替换;而const常量有具体的类型,会编译检查,会报编译错误
- 宏能定义一些函数,方法;const不能
- 使用大量宏,容易造成编译时间久,每次都需要重新替换
- 宏仅仅是展开,有多少地方使用,就展开多少次,不会分配内存。(宏定义不分配内存,变量定义分配内存。);而const常量会在内存中分配(可以是堆中也可以是栈中),const 可以节省空间,避免不必要的内存分配
宏 | const |
---|---|
#define PI 3.14159 //常量宏 | const doulbe Pi=3.14159; //此时并未将Pi放入ROM中 |
double I=PI; //预编译期间进行宏替换,分配内存 | double i=Pi; //此时为Pi分配内存,以后不再分配! |
double J=PI; //再进行宏替换,又一次分配内存 | double j=Pi; //没有内存分配 |
- const定义常量从汇编的角度来看,只是给出了对应的内存地址,而不是象#define一样给出的是立即数,所以,const定义的常量在程序运行过程中只有一份拷贝(因为是全局的只读变量,存在静态区),而 #define定义的常量在内存中有若干个拷贝。
- 编译器通常不为普通const常量分配存储空间,而是将它们保存在符号表中,这使得它成为一个编译期间的常量,没有了存储与读内存的操作,使得它的效率也很高。
2.2 typedef和#define
- define是文本替换,属于预编译指令,本身不参与编译,除非希望替换的文本中有
;
否则不用加。
typedef是类型替换,语句的一种,结尾必须有;
- define写在方法/函数中则作用域从写的地方开始有效,直至使用
#undef
(不写此指令则后面一直有效)。typedef写在方法/函数中则作用域 只在此方法/函数中有效。 - 若使用 typedef char * MyString; 则
MyString s1,s2
等价于char *s1; char *s2;
若使用 #define MyString char * 则MyString s1,s2
等价于char *s1,s2
即char *s1; char s2
再次说明了typedef
是类型替换,直接参与编译,而define
只是简单的文本替换。
iOS学习——#define、const、typedef的区别的更多相关文章
- C++ —— 非类中使用const定义常量的初始化,以及#define和typedef的区别
总结一下在非类中使用const关键字定义常量时的初始化问题,亲测VS2015.顺便记录#define宏和typedef的区别. 1 首先对const声明的常量的初始化做简单小结: , w2 = , w ...
- 【C语言笔记】#define与typedef的区别
1.#define define是预处理指令,在编译时不进行任何检查,只进行简单的替换 宏定义的一般形式为: #define 宏名 字符串 这里所说的字符串是一般意义上的字符序列,不要和C语言中的字符 ...
- define和typedef的区别
define和typedef的区别 define是单纯的字符替换,typedef是重新定义了新的类型 #include <stdio.h> #define CHAR1 char* type ...
- #define const typedef
#define用法 1. 定义简单的常数:定义常量,便于修改 #define N 1000 2. 定义简单的函数:注意多使用括号 define可以像函数那样接受一些参数,如下: #define max ...
- #define\const\inline的区别与联系
总结: const用于代替#define一个固定的值,inline用于代替#define一个函数.是#define的升级版,为了消除#define的缺陷. 参考内容:http://www.cnblog ...
- #define 和typedef的区别
typedef和define的详细区别 2011-04-19 15:11 firnow firnow 字号:T | T 对于都可以用来给对象取一个别名的Typedef和define来说,是有区别的.本 ...
- 宏定义#define和typedef的区别和典型范例题目辨析
宏定义#define pStr char* ,是直接把程序中出现pStr的地方替换成char* ,直接替换: typedef char * pStr; 是给char*定义一个别名叫做 pStr; ...
- define与typedef的区别
define: 发生在预处理阶段,也就是编译之前,仅仅文本替换,不做任何的类型检查 没有作用域的限制 typedef: 多用于简化复杂的类型声明,比如函数指针声明:typedef bool (*fun ...
- iOS学习笔记之typedef
typedef unsigned long long weiboId; typedef 定义一个使用方便的类型,谓之为“宏定义“. unsigned long long 是一种无符号的长长整型.本应该 ...
随机推荐
- VS2017 提示警告 IDE0006
MS的错误帮助:https://github.com/dotnet/roslyn/wiki/Diagnosing-Project-System-Build-Errors 看起来好复杂- 其实嘛- 检查 ...
- Initialize the shader 初始化着色器
目录 Loads the shader files and makes it usable to DirectX and the GPU 加载着色器文件并使其可用于DirectX和GPU Compil ...
- js原型与原型链探究
原型有一个非常重要的属性叫 prototype 一.先写一个简单的例子,看看 A的原型和A的实例 分别是什么 function A() {} var a = new A() console.log(a ...
- POSIX共享内存
DESCRIPTION 共享内存是最快的可用IPC形式.它允许多个不相关(无亲缘关系)的进程去访问同一部分逻辑内存. 如果需要在两个进程之间传输数据,共享内存将是一种效率极高的解决方案.一旦这样的内存 ...
- 06flask_migrate
1,flask-migrate介绍: 因为采用db.create_all()在后期修改字段的时候不会自动的映射到数据库中,必须删去表,然后运行 db.create_all()才会重新映射,这样不符合我 ...
- DWM1000 自动应答代码实现与实例
这一节继续继承之前帧过滤部分,首先补充一下关于帧过滤部分,如果将目标地址设置为0xFFFF,则同一个网络(物理频道与PANID 都相同),所有节点都应该收到这条信息,这个信息为广播信息,0xFFFF为 ...
- KindEditor富文本编辑器, 从客户端中检测到有潜在危险的 Request.Form 值
在用富文本编辑器时经常会遇到的问题是asp.net报的”检测到有潜在危险的 Request.Form 值“一般的解法是在aspx页面 page 标签中加上 validaterequest='fa ...
- 微信网页悬浮窗交互效果的web实现
一.微信的悬浮窗交互效果 微信更新后,发现多了个悬浮窗功能.公众号阅读,网页浏览回退后默认会出现.再点击,可以回到刚才阅读的地方.于是,再也不会遇到回复老婆的信息,再切换回来重新找刚才阅读东西的麻烦了 ...
- Web版记账本开发记录(三)开发过程遇到的问题小结2
问题1,获得当前时间 Date d = new Date(); SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss ...
- CFUpdate高速模式下出现Error #2038提示的解决方案
使用CFUpdate上传文件,在IE模式下是正常的,切换到高速模式下出现提示Error #2038错误,文件无法上传. 向作者了解到需要设置challs_flash_update函数中的a.url为绝 ...