static、const、extern关键字
)
前言
继属性关键字博客,这里补充static、const、extern关键字的学习。
static
static既可以修饰局部变量,也可以修饰全局变量。用static修饰的变量我们称为静态变量。
静态变量:生命周期与程序运行时间相同,只初始化一次,在程序启动时创建,在程序结束时销毁。
修饰局部变量
称为静态局部变量。
对比一下下面两个代码:
objc
-(int)add {
int a = 0;
a++;
return a;
}
- (void)viewDidLoad {
[super viewDidLoad];
for (int i = 0; i < 5; i++) {
NSLog(@"%d", [self add]);
}
}

objc
-(int)add {
static int a = 0;
a++;
return a;
}
- (void)viewDidLoad {
[super viewDidLoad];
for (int i = 0; i < 5; i++) {
NSLog(@"%d", [self add]);
}
}

- 代码一:a作为局部变量
在add代码块中,a作为一个局部变量,当我们重复调用add方法时,局部变量a也在不断地被分配空间初始化与销毁。当一次add方法结束后,即变量超出作用域时,a被销毁,下一次调用时又重新分配内存空间。
也就是说它的生命周期是函数调用时开始,函数结束后销毁。
底层逻辑实际上是调用add方法时,系统在栈区上分配一块内存,然后a = 0存入该内存,每次执行函数时,都是在栈上对a进行操作,当add方法返回时,栈被销毁,再次调用时,系统重新为a分配一次栈内存。
- 代码二:a作为静态局部变量
当使用static修饰局部变量时,变量被称为静态局部变量。与全局变量、静态全局变量一样,静态局部变量也是存储在静态存储区的。由于存储在静态存储区,因此这里的内存会直到程序结束才销毁。
也就是说它的生命周期是程序开始时分配,程序结束时销毁。
这里我们重点总结一下静态局部变量的特点:
- 存储在静态内存区:静态局部变量与局部变量不同,它不存储在栈内存中,而是静态内存区域。静态内存区中的变量在程序运行期间一直存在。
- 初始化只发生一次:静态局部变量的初始化仅在第一次进入它的作用域时发生。一旦被初始化,在函数的每次调用时,静态局部变量的状态都会得到保持,它们的值会被保留,一直保持不变,不会在后续函数调用中重新初始化。
修饰全局变量
称为静态全局变量。
下面我们通过代码对比一下有没有static修饰全局变量的区别:
- 没有static修饰符
定义一个全局变量b,存储区在静态存储区,直到程序结束才销毁。
objc
#import "AViewController.h"
#import "BViewController.h"
@interface AViewController ()
@end
@implementation AViewController
int b = 10;
在别的界面想调用它时,使用extern关键字来引用这个全局变量。
objc
#import "BViewController.h"
@interface BViewController ()
@end
@implementation BViewController
extern int b;
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor greenColor];
NSLog(@"%d", b);
}
- 有static修饰符
objc
@interface AViewController ()
@end
@implementation AViewController
static int b = 10;
这时我们想在别的地方调用b这个全局变量时,会出现报错:

这说明这时我们已经不能在其它文件中访问到这个全局变量b了。
总结
- static修饰局部变量时,将分配在栈区改为分配在静态存储区,改变了局部变量的生命周期。
- static修饰全局变量时,将源程序所有文件可见改为只在申明自己的文件可见,改变了作用域。
const
const主要强调当前变量无法被修改。
objc
const int c = 1;
c = 2;
这样就会出现提示我们c无法被修改的错误:

这样相当于用#define来定义,但const可以指定变量的类型,#define不能。
objc
#define c 1
extern
extern主要是跨文件之间的变量共享和函数声明,也就是用于声明在其它源文件中定义的全局变量或函数。它用来告诉编译器某个标识符的定义在其它文件中,但在当前文件中要使用它。
声明全局变量
这个使用的demo已经在上面展示。
声明函数
表示函数定义在其它源文件,但允许在该源文件中调用定义的函数。
objc
void test(void) {
NSLog(@"Hello iOS");
}
objc
extern void test(void);
- (void)viewDidLoad {
[super viewDidLoad];
test();
}
还有一种写法:
extern声明一般写在头文件中,因此可以在需要的源文件中包含该头文件,以便多个源文件可以共享相同的声明。
objc
#ifndef Header_h
#define Header_h
extern int b;
#endif /* Header_h */
objc
#import "BViewController.h"
#import "Header.h"
@interface BViewController ()
@end
@implementation BViewController
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(@"%d", b);
}
总结
extern关键字使得不同文件可以共享相同的变量和函数,实现跨文件的共享和使用。