首页 > 代码库 > 关于extern和static关键字引出的一些关于作用域和链接属性和存储类型的问题

关于extern和static关键字引出的一些关于作用域和链接属性和存储类型的问题

在进入正题前我们必须了解一些概念:

标识符:标识符不仅仅代表着变量的名字,main()函数的main也是一个标识符,这点很重要。

存储类型:即变量的存储位置及其生存周期:
静态区:分为两块
.date 已显式初始化的全局变量了静态变量
.bss 存放未初始化的全局或者静态变量

注意:
静态变量的初值是在编译时就进行初始化了;
意思就是用static修饰的变量赋过数值的话就保存为他的初值,如果没有初始化的话就赋值为零,且整个程序只初始化一次;
即不管static int i = 1;或者这 static int a 在程序中的什么位置;分别由编译器初值装入1和0保存在静态区
注意初始化只执行一次;看如下例子:
#include <stdio.h>

void add()
{
  static a;
  static b = 1;
  printf("%d\t",a++);
  printf("%d\n",b++);
}

int main()
{
  int i = 0;
  for(;i<5 ;i++)
  {
    add();
  }
return 0;
}
的结果为:
0 1
1 2
2 3
3 4
4 5


堆栈区:

栈:系统自动分配和释放:例如局部变量函数或者代码块结束时释放因为就是局部变量存储在栈区。
堆:开发者自己生申请和释放(例如调用void *malloc())。它的生存周期是开发者决定的。
当你使用malloc的是后被造出来,free后被销毁。

常量区:存储常量数据;编译完成后到程序结束都存在,可以访问但是不能被修改。


链接属性:
假设我们有很多.c文件一起生成一个可执行文件例如:
test0.c   test1.c    test2.c
|       |        |
|       |               |
|         |               |
test0.o     test1.o          test2.o
|        |       |
——————————————链接
                    |
                   test

链接的作用就是将各个二进制代码文件链接生成一个可执行文件所以不管是我们写了多少个c文件最后都是要被合成一个的,
这个时候我们就该考虑一个问题各个文件的标识符是否公用,因此便引出了链接属性。

 

c规定链接属性分为三种:
external(全局的):各个文件访问的是同一个标识符。
internal(局部的):标识符只被该文件中定义后的地方能访问。
none(无链接属性):没有链接属性。


作用域:即标识符能被访问的代码区域大小。
代码块作用域:在代码块中定义的标识符只在定义的开始和代码块的时候能被访问,即使是被声明为静态不能使作用域扩大,这个下面会提到。
文件作用域:一般指全局变量和函数,即在整个文件中从定义的起始的位置后都能被访问。
原型作用域:即形参的作用域,一般就是在整个函数代码块中有效,它的存在是防止我们多次在函数内定义一个和形参标识符的名字冲突的标识符
因为这样我们会失去形参的值。
函数作用域:这个是用来说代码标号的作用区域的,所以他和goto有关,呵呵,我看了一眼就忘了。

下面来看几个关键字()

auto:进入程序时在栈创建,程序结束自动释放。一般局部变量自带auto属性。所以用的很少。

static:
1:用于修饰局部变量时修改的是其存储类型,使其成为静态存储。至于局部变量静态存储后的变量有什么改变参照上文的解释和例子。但是作用域不改变。
2:修饰全局标识符时,意思是将全局变量的external属性修改为internal。但是作用域不改变。
3:修饰函数时是修改它的链接属性external属性修改为internal。但是作用域不改变;

extern:
1.修饰变量时声明这个变量定义在别的文件中或者本文件其他位置的external属性的变量,一般用来修饰全局标识符(变量函数);
注意:
如果我们在标识符声明时,一旦是在函数块外部声明,那么编译器默认加多上一个external属性,而不是extern修饰符。这很重要容易混淆。
而在代码块中声明的局部变量则会被带上一个intenral的链接属性。但这不代表他只能在代码块的属性是intenral的链接属性赋予的。
真正的原因是因为局部变量被看作一个auto类型的变量。

register:即存储在寄存器中的变量,寄存器有什么特点大家都知道寄存器的取数效率很高常用于重复的变量运算。注意
不能用全局变量去申请,一般默认为auto,这和全局变量的生命周期有关。

 

总结:千万不能把extern和external与static与internal混淆。他们的具体解释看上文。
狗日的公司笔试其和考试题经常拿这个来考人。就像下面这个:
#include "stdio.h"
int a=1;

int f(int c)
{
  static int a=2;
  c=c+1;
return (a++)+c;
}
main()
{
  int i,k=0;
  for(i=0;i<2;i++)
  {
    int a=3;
    k+=f(a);
  }
  k+=a;
  printf("%d\n",k);
}
我们只要根据上文提到的知识:把变量表示符一换,就可以了:
#include "stdio.h"
int a=1;

int f(int c)
{
  static int b=2;
  c=c+1;
return (b++)+c;
}
main()
{
  int i,k=0;
  for(i=0;i<2;i++)
  {
    int d=3;
    k+=f(d);
   }
  k+=a;
  printf("%d\n",k);
}

问题及解决,妈妈再也不用担心我的学习。

关于extern和static关键字引出的一些关于作用域和链接属性和存储类型的问题