美文网首页窥探iOS底层原理
static、const、extern的正确使用方式

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

作者: 小李小李一路有你 | 来源:发表于2018-12-06 12:52 被阅读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
      • 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";
    
    

    相关文章

      网友评论

        本文标题:static、const、extern的正确使用方式

        本文链接:https://www.haomeiwen.com/subject/foancqtx.html