[iOS]static、extern、const关键字比较

07-19 1401阅读

[iOS]static、extern、const关键字比较

文章目录

  • [iOS]static、extern、const关键字比较
    • 全局区地址如何分配
      • 静态区安全测试
      • static、extern、const关键字
        • 具体的例子
          • 关于extern关键字
          • 关于static关键字
          • 关于静态变量
            • 类的静态变量
            • 参考博客

              介绍这三个关键字之前先补一下课

              全局区地址如何分配

              先来一段代码

              不难看出下面的clA bssA bssStr1属于未初始化的全局变量和静态变量,在BSS段

              clB bssB bssStr2属于已初始化的全局变量和静态变量,在DATA段

              int clA;
              int clB = 10;
              static int bssA;
              static NSString *bssStr1;
              static int bssB = 10;
              static NSString *bssStr2 = @"bss";
              - (void)testConst {   
              	NSLog(@"clA == \t%p",&clA);
                  NSLog(@"bssA == \t%p",&bssA);
                  NSLog(@"bssStr1 == \t%p",&bssStr1);
                  
                  NSLog(@"clB == \t%p",&clB);
                  NSLog(@"bssB == \t%p",&bssB);
                  NSLog(@"bssStr2 == \t%p",&bssStr2);
              }
              

              然后我们看打印结果

              它们的内存分配有什么规律

              [iOS]static、extern、const关键字比较

              可以看出:

              未初始化的全局变量和静态变量,在BSS段

              BSS段的地址分配时,是低地址 -> 高地址

              已初始化的全局变量和静态变量,在DATA段

              DATA段的地址分配,与变量定义的顺序无关

              静态区安全测试

              静态变量的作用范围是当前文件内。

              相当于引用别的文件时,底层会深拷贝一份静态变量,放在了自己的文件中,以后访问及操作的都是本文件内的这个变量,对别的文件没有影响。

              当前文件更改静态变量后,本文件内再访问,是更改后的值,但不影响别的文件中的这个静态变量的值。

              别的文件引入静态变量后,拿到的是静态变量的初始值,修改后再访问是自己修改后的值。

              static、extern、const关键字

              extern

              extern关键字用来声明变量或者函数是一个外部变量或者外部函数,也就是说告诉编译器该变量是在其他文件中定义的,编译的时候不要报错,在链接的时候按照字符串寻址可以找到这个变量或者函数

              如果A.h中定义了全局变量比如int a;,那么在其他文件中的函数调用变量a的时候需要在对应头文件或者定义文件中(保证在使用这个变量前)使用extern int a;来声明这个变量,但是这样做有一个弊端,首先如果A.h中集中定义了大量的全局变量供其他文件使用,那么其他的调用文件中会重复的出现大量的extern语句,第二,如果其他文件直接引用A.h,那么会造成全局变量的重复定义,编译不过,等等

              所以我们应该

              1、在定义文件中定义全局变量, 比如A.m中定义全局变量 int aa;

              2、在对应的头文件A.h中声明外部变量 extern int aa;

              3、在使用aa变量的文件B.m中包含A.h;

              在编译阶段,B编译单元虽然找不到该函数或变量,但它不会报错,它会在链接时从A编译单元生成的目标代码中找到此函数。

              static

              使用static修饰变量,就不能使用extern来修饰,即static和extern不可同时出现

              static修饰的全局变量的声明与定义同时进行,即当你在头文件中使用static声明了全局变量,同时它也被定义了。

              static修饰的全局变量的作用域只能是本身的编译单元。如果有多个文件包含了定义static变量的头文件,在其他编译单元使用它时,只是简单的把其值复制给了其他编译单元,其他编译单元会另外开个内存保存它,在其他编译单元对它的修改并不影响本身在定义时的值。(与头文件中定义const类似)

              即在其他编译单元A使用它时,它所在的物理地址,和其他编译单元B使用它时,它所在的物理地址不一样,A和B对它所做的修改都不能传递给对方

              多个地方引用静态全局变量所在的头文件,不会出现重定义错误,因为在每个编译单元都对它开辟了额外的空间进行存储。

              一般定义static 全局变量时,都把它放在.m文件中而不是.h文件中,这样就不会给其他包含此头文件的编译单元里边重复生成变量。

              在标准C++中引入命名空间之前,程序必须将名字声明为static,使他们用于当前编译单元。C++文件中静态声明的使用从C语言继承而来,在C语言中,声明为static的局部实体在声明它的文件之外不可见。

              C++不赞成文件静态声明。C++标准取消了在文件中声明静态声明的做法。应该避免static静态声明,而在源文件中使用未命名的命名空间,在未命名的命名空间中定义变量。

              未命名的命名空间仅在文件内部有效,其作用范围不会横跨多个不同的文件。

              具体的例子

              关于extern关键字

              在头文件里这么写是合理的

              //.h
              static NSString * const myString = @"foo";
              

              但是其实这是不正确也并不安全的一种写法

              想让这个常量字符串被其他的类所正确使用

              那么在我的头文件里应该这么声明

              //.h
              extern NSString * const myString;
              

              然后在每个引用头文件的源文件内

              //,m
              NSString * const myString = @"foo";
              

              何意呢家人们 为什么要这么写 到底安全在哪里?

              在每个编译单元内,也就是通俗说在每个.m文件内

              用static const修饰的myString内容都是 foo 没问题

              但这些myString其实是不同的对象

              static修饰的全局变量的作用域只能是本身的编译单元。如果有多个文件包含了定义static变量的头文件,在其他编译单元使用它时,只是简单的把其值复制给了其他编译单元,其他编译单元会另外开个内存保存它,在其他编译单元对它的修改并不影响本身在定义时的值。

              也就是说这里的static和const功能重复了

              多个.m文件文件内存在的都是myString对象的复制

              并没有实现多个文件共同使用咱们的一个myString对象

              而extern关键字使我们的myString对象变成可共同使用的外部变量

              然后就是注意extern的使用事项

              1、在定义文件中定义全局变量, 比如A.m中定义全局变量 int aa;

              2、在对应的头文件A.h中声明外部变量 extern int aa;

              3、在使用aa变量的文件B.m中包含A.h;

              关于static关键字

              关于前面提到static的部分

              我们来一段栗子

              先在test1.h定义字符串 g_str

              //test1.h
              #ifndef TEST1H
              #define TEST1H
              static char g_str[] = "123456"; 
              void fun1();
              #endif
              

              在test1.cpp中使用变量 g_str

              //test1.cpp
              #include "test1.h"
              void fun1() {
              	cout 
              	cout 
              	g_str[0] = 'a';
              	cout 
              	cout 
              	fun1(); // a23456
              	fun2(); // 123456
              }
              
                  counter++;
              }
              + (NSInteger)getCounter {
                  return counter;
              }
              @end
              
                  public:
                      void myMethod();
              };
              
                  return a + b;
              }
              
VPS购买请点击我

文章版权声明:除非注明,否则均为主机测评原创文章,转载或复制请以超链接形式并注明出处。

目录[+]