ios开发基础学习笔记(五)--static、const和extern的使用

前言

大家好,我是milo,在学习ios开发中,我们有时候会用到static(静态变量)、const(常数)、extern(外部变量),在这篇文章中,我将讲解它们的基本使用。我讲解的顺序是extern->static->const,为什么有个顺序呢,那么请往下看。

extern

全局变量extern,也称之为外部变量,是在方法外部定义的变量。它不属于哪个方法,而是属于整个源程序。作用域是整个源程序。如果全局变量和局部变量重名,则在局部变量作用域内,全局变量被屏蔽,不起作用。

上面这段话理解起来有点抽象,下面演示一个简单的例子:

JJExtern.h文件
#import <Foundation/Foundation.h>

NSString *flag = @"JJExtension";

@interface JJExtern : NSObject

@end

定义了一个字符串flag

main.m文件
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[]) {

    extern NSString *flag;
    
    NSLog(@"%@",flag);
    
    return 0;
}

打印结果如下:
2018-05-12 16:46:01.643949+0800 oc练习[1810:181852] JJExtension

从以上例子可以看出,main.m无需导入JJExtern的头文件,直接在 NSString *flag前面加上extern就可以取得JJExtern内的flag值。需要注意的是,extern修饰的变量名必须是和JJEXtern下变量名的一致的,即都为flag,否则就会提示找不到。还有一点要注意的是,extern修饰的变量是没有真正的内存的。

总结:
<1>要想访问全局变量可以在前面加extern
<2>extern修饰的变量没有真正内存

那么问题来了,即然只需要extern就能得到并修改其他文件的变量,此不是很安全?因为随时会被人改掉?该怎么办?
答案就是使用static修饰变量,那么该变量就只能在本文件中修改,其他文件无法使用extern获取变量。

static

static既可修饰全局变量,又可以修饰局部变量。

1、修饰全局变量

以前面的例子来说,在 JJExtern 的 NSString *flag = @"JJExtension"; 前面加static,如下:

#import <Foundation/Foundation.h>

static NSString *flag = @"JJExtension";

@interface JJExtern : NSObject

@end

再次运行main.m,编译器报错如下图

static修饰后extern就找不到flag.png
所以只要在全局变量前加static,那么这个全局变量的作用域就会缩小到当前文件,外界就不能访问了。

总结:static修饰全局变量,保证全局变量安全,外界不可访问与修改,作用域仅限于当前文件。

2、修饰局部变量

下面先看示例代码:

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;
}

修饰局部变量时,作用域仅限于test函数的大括号,其他地方都不顶用 。test这个函数中如果不加static,那么a打印出来的结果永远是1,因为每当调用一次函数,就会定义一个新的变量,每次a的值都是零,a++后就是1 。

但是加上static后,含义就不一样了,打印的结果就是1,2,3......因为被static修饰的变量只会初始化一次,永远都只有一份内存,所以当第一次调用test函数时,a有一个内存空间,并且值是0,第二次再调用test函数时由于int a被 static 修饰,所以不会再初始化新值,它会拿到之前的那份内存a++,就会变为1,以此类推,之后就会变为2,3,4......

总结:
<1>让局部变量只初始化一次
<2>局部变量在程序中只有一份内存
<3>保住所修饰变量的命,保证它不会挂,直到程序结束,这个局部变量才会销毁

const

一句话概括,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;  
int * const px = &x; // 让指针px指向变量x(此时const右边是p)
px = &y;    // 改变px的指向,出错:Read-only variable is not assignable  
(*px) += 2; // 改变px指向的变量x的值  
int x = 1;  
int y = 2;  
const int * const px = &x; // 让指针px指向变量x(此时const右边是*p和p)
px = &y;    // 改变px的指向,出错:Read-only variable is not assignable  
(*px) += 2; // 改变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”

}

想深入了解可以参考http://www.cocoachina.com/bbs/read.php?tid=1708764
https://www.cnblogs.com/lulipro/p/7460206.html,分别是oc指针讨论和c指针详解。

引用了以下链接的资料,在此表示感谢:
http://www.cocoachina.com/bbs/read.php?tid=1708764
https://blog.csdn.net/jymn_chen/article/details/18900201
https://www.cnblogs.com/lulipro/p/7460206.html
https://blog.csdn.net/gezi0630/article/details/51993934

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容