窥探iOS底层原理

static、const、extern的正确使用方式

2018-12-06  本文已影响0人  小李小李一路有你

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就能得到并修改其他文件的变量,这样不是很不安全?因为随时都会被人改掉,怎么办??

答案:

使用接下来所讲的 static关键字修饰变量,那么该变量就只能在本文件中修改,其他文件无法使用extern获取变量

2.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
编译时刻 预编译(在编译前处理) 编译阶段
编译检查 不做检查,不会报编译错误,单纯替换功能,用宏定义的函数会报参数类型错误 会做编译检查,会报编译错误
宏的好处 宏能定义一些函数、方法 例如RGB函数 不能
宏的坏处 使用大量的宏,容易造成编译时间久每次都需要重新替换

三段代码理解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:常量 
}

4. 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联合使用


///>  In the header file

extern NSString *const EOCStringConstant;



///>  In the implementation file
NSString *const EOCStringConstant = @"VALUE";

上一篇下一篇

猜你喜欢

热点阅读