static、const、extern的正确使用方式
static、const、extern的正确使用方式
1.extern
全局变量extern,也称之为外部变量,是在方法外部定义的变量。它不属于那个方法,而是属于整个源程序。作用于是整个程序。如果全局变量和局部变量重名,则在局部变量作用域内,全局变量被屏蔽,不起作用
///> DDExtern.h
#import <Foundation/Foundation.h>
NSString *flag = @"DDExtension";
@interface DDExtern : NSObject
@end
定义了一个字符串 flag
///> main.m
#import <Foundation/Foundation.h>
int main(int argc, const char \* argv\[\]) {
extern NSString *flag;
NSLog(@"%@",flag);
return 0;
}
打印结果:DDExtension
从例子中可以看出,main.m无需导入JJExtern的头文件,直接在NSString *flag前面加上extern关键字就可以取到JJExtern的flag值。
需要注意的是,extern修饰的变量名必须是和Extern下的变量名一致,即都为flag,否则会都提示找不到。
还需要注意extern修饰的变量是没有真的内存的。
-
总结:
- 想要访问全局变量,可以在变量前加一个extern
- extern修饰的变量没有真正的内存
问题:
既然只需要extern就能得到并修改其他文件的变量,这样不是很不安全?因为随时都会被人改掉,怎么办??
答案:
使用接下来所讲的 static关键字修饰变量,那么该变量就只能在本文件中修改,其他文件无法使用extern获取变量
2.static
static 既可以修饰全局变量,又可以修饰局部变量。
-
修饰全局变量
使用之前的例子,在JJExtern的 NSString *flag = @"JJExtension"; 前面加 static,如下
///> JJExtern.h #import <Foundation/Foundation.h> static NSString *flag = @"DDExtension"; @interface JJExtern : NSObject @end
再次运行main函数 编译会报错
note_staticAbout_01.png
所以只要在全局变量前加static,那么这个全局变量的作用域就会缩小到当前文件,外界就不能访问了
-
总结:
- static修饰全局变量,保证全局变量安全,外界不可以访问与修改,作用域仅限于当前文件。
-
-
修饰局部变量:
代码:
///> main.m
void test() {
static int a = 0;
a++;
NSLog(@"a = %d", a);
}
int main(int argc, const char \* argv\[\]) {
@autoreleasepool {
for (int i = 0; i<3; i++) {
test();
}
}
return 0;
}
/** 输出结果:
* 2018-12-05 19:20:55.494405+0800 tesy[11959:2261816] a = 1
* 2018-12-05 19:20:55.499893+0800 tesy[11959:2261816] a = 2
* 2018-12-05 19:20:55.505727+0800 tesy[11959:2261816] a = 3
*/
修饰局部变量时,作用域仅限于test函数的大括号内,其他地方都不可以使用。test这个函数中如果不添加 static,那么a打印出来永远都是1,因为在运行完此段函数 局部变量a就会被释放。重新执行函数时a++为0+1.
加上static之后的含义就改变了,结果为1,2,3。因为被static修饰的变量只会初始化一次,永远都只有一份内存,所以当第一次调用test函数时a就已经被初始化了,a有一个内存空间并且值为0,第二次调用test函数由于a被static修饰,所以不会再初始化新的值,它会拿到之前的那份内存进行a++操作,就会变成1,以此类推。
-
总结:
- 让局部变量只初始化一次
- 局部变量在内存中只有一份内存
- 直到程序结束才会被销毁
3. const
const的作用和宏类似,苹果不推荐使用宏定义,推荐使用const,所以在swift中苹果抛弃了宏的使用。
- const 和 宏的区别
\ \ | 宏 | const |
---|---|---|
编译时刻 | 预编译(在编译前处理) | 编译阶段 |
编译检查 | 不做检查,不会报编译错误,单纯替换功能,用宏定义的函数会报参数类型错误 | 会做编译检查,会报编译错误 |
宏的好处 | 宏能定义一些函数、方法 例如RGB函数 | 不能 |
宏的坏处 | 使用大量的宏,容易造成编译时间久每次都需要重新替换 |
- 使用过多的宏会消耗大量编译时间。
const的作用就是使右边的变量,只可读,不可修改
三段代码理解const
int x = 1;
int y = 2;
const int *px = &x; // 让指针px指向变量x(此时const右边是*p)
px = &y;// 改变指针px的指向,使其指向变量y
*px = 3; // 改变px指向的变量x的值,出错:Read-only variable is not assignable
int x = 1;
int y = 2;
const int *px = &x; // 让指针px指向变量x(此时const右边是*p)
px = &y; // 改变指针px的指向,使其指向变量y
*px = 3; // 改变px指向的变量x的值,出错:Read-only variable is not assignable
int x = 1;
int y = 2;
const int *px = &x;// 让指针px指向变量x(此时const右边是*p)
px = &y; // 改变指针px的指向,使其指向变量y
*px = 3; // 改变px指向的变量x的值,出错:Read-only variable is not assignable
上面的三段代码处理的是基本数据类型,我们知道OC语言是C语言的超集,所以上面部分基本数据类型的处理OC与C一样。
但是我们知道OC是C语言的超集,OC中还有NSString等的数据类型,它们的本质是个结构体,所以在处理指针方面与基本数据类型不同
代码如下:
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[]) {
NSString const *name = @"milo";// const修饰*name
NSLog(@"%@",name);// 打印结果“milo”
name = @"vicky";// 在oc中NSString等类的值不是通过*name访问的,而是通过name访问的,这就是和c语言的指针的区别,但还是遵循const右边是谁,谁就只可读的原则。
NSLog(@"%@",name);// 打印结果“vicky”
}
objective-c语言代码
- (void)viewDidLoad {
[super viewDidLoad];
// 定义变量
int a = 1;
// 允许修改值
a = 20;
// const两种用法
// const:修饰基本变量p
// 这两种写法是一样的,const只修饰右边的基本变量b
const int b = 20; // b:只读变量
int const b = 20; // b:只读变量
b = 1; // 不允许修改值
// const:修饰指针变量\*p,带\*的变量,就是指针变量.
// 定义一个指向int类型的指针变量,指向a的地址
int *p = &a;
int c = 10;
p = &c;
// 允许修改p指向的地址,
// 允许修改p访问内存空间的值
*p = 20;
// const修饰指针变量访问的内存空间,修饰的是右边*p1,
// 两种方式一样
const int *p1; // *p1:常量 p1:变量
int const *p1; // *p1:常量 p1:变量
// const修饰指针变量p1
int * const p1; // *p1:变量 p1:常量
// 第一个const修饰*p1 第二个const修饰 p1
// 两种方式一样
const int * const p1; // *p1:常量 p1:常量
int const * const p1; // *p1:常量 p1:常量
}
-
总结:
- const仅仅用来修饰右边的变量(基本数据变量px 指针变量*px)
- 被const修饰的变量是只读的
4. static、const结合使用
- static与const作用:声明一个只读的静态变量
- 开发使用场景:在
一个文件中
经常使用的字符串常量,可以使用static与const组合
///> 开发中常用static修饰全局变量,只改变作用域
///> 为什么要改变全局变量作用域,防止重复声明全局变量。
///> 开发中声明的全局变量,有些不希望外界改动,只允许读取。
///> 比如一个基本数据类型不希望别人改动
///> 声明一个静态的全局只读常量
static const int a = 20;
///> staic和const联合的作用:声明一个静态的全局只读常量
///> iOS中staic和const常用使用场景,是用来代替宏,把一个经常使用的字符串常量,定义成静态全局只读变量.
///> 开发中经常拿到key修改值,因此用const修饰key,表示key只读,不允许修改。
static NSString * const key = @"name";
///> 如果 const修饰 *key1,表示*key1只读,key1还是能改变。
static NSString const *key1 = @"name";
5. extern与const联合使用
- 开发中使用场景:在
多个文件中
经常使用的同一个字符串常量,可以使用extern与const组合。 - 原因:
- static与const组合:在每个文件都需要定义一份静态全局变量。
- extern与const组合:只需要定义一份全局变量,多个文件共享。
- 全局常量正规写法:开发中便于管理所有的全局变量,通常搞一个GlobeConst文件,里面专门定义全局变量,统一管理,要不然项目文件多不好找。
///> In the header file
extern NSString *const EOCStringConstant;
///> In the implementation file
NSString *const EOCStringConstant = @"VALUE";