C语言中的static和extern关键字——【链接属性】和【存储类型】角度解析

在c语言中,static关键字具有“一词多义”,他可以放在变量定义前,也可以放在函数定义前,其中位于代码块内的static和代码块外的static又是不一样的;与之相伴的extern也是同样地蜜汁神奇。以下有一个例子:

int        a = 5;
extern int b;
static int c; 
int fun1(int d)
{
	int          e = 10;
	register int f;
        static   int g=10;
        extern   int a;
    ......
    {
        int         e;
        int         a;
        extern int  h;
        ......
       
    }
    ......
    {
        int x;
        int e;
        ......
    }
  ...
}

static int i(void)
{
    ....
}

这里面出现了许多static和extern关键字,并且在不同地方还使用了同样的标识符,如何解释各个static和extern的作用?


首先,在C中,有一个链接属性(Linkage)的概念,描述了在不同文件中的标识符实体归属的关系。

链接属性有三种:外部(external),内部(internal)和无(none).

1.外部属性:指该属性的标识符在不同文件中都代表同一个实体,声明方法是使用关键字external,这也是最常用的方法。例如第2行就显式地声明了b是外部属性。缺省时,代码块外的变量声明/定义和函数的定义,都属于external属性,所以第1行虽然没有extern关键字,但事实上和第2行的属性并无差异。同时按照之前的定义,第4行的函数fun1,也是外部链接属性,在其他文件中可以被调用。

2.内部属性:被声明为internal的标识符在整个文件中都表示同一个实体。如果在代码块外定义的变量或者是独立的函数,想要作用域只限于本文将,就需要声明为internal类型,方法就使用关键字static,第3行就是一个声明internal属性变量的例子(然而第8行的static并不是在声明internal链接属性,后面会分析到);第27行的函数也被声明为静态函数,即该函数只能在本文件中被访问,如果一个函数只是为了服务上层函数,而不会被单独用来实现某功能,那么就应该被声明为static类型,防止在外部被误调用,也增加了程序的可读性。

3.无属性:在代码块内,没有特别声明的变量就是none属性,表示一个独立的个体,如第6行中的int e = 10; 变量e在函数fun1的中括号内、e被再次声明前起作用,即作用域是5-10,18,24行。在第11-17行的代码段中,又新定义了一个e,因此第6行中定义的e,在这个代码段中不起作用。直到第18行代码段结束,第12行的e被回收,第6行定义的e又可以使用了。同样,在第19-23行,代码段中又新定义了e,第6行定义的e不可访问,直到23行,该代码段结束。


此外,还需要引入存储类型的概念。机器中存储变量的地方有三个:普通内存、运行堆栈、寄存器,分别对应3种类型的变量:静态变量(static)、自动(automatic)、寄存器(register)。

寄存器变量就不讲了,就是使用register关键字声明的变量,让编译器把这个值放入cpu的硬件寄存器,但事实上,编译器往往不会照做,而是忽略这个命令,因为编译器有自己的方法,自动把一些使用频繁的变量放入寄存器,提升运行效率。编译器的自动处理比程序员敲出来的代码不知道高到哪里去了。所以除非你在编写一个内存只有几十K的嵌入式芯片,把内存和寄存器的使用情况搞的一清二楚,并且关闭了编译器的自动优化,编译器或许会听你的安排。

自动类型的变量也是在代码块内部声明变量的默认类型。这些变量存储在运行堆栈内,代码块一结束,变量也就丢弃了,之前所占据的内存空间就会被拿出来继续分配。

静态变量存储在静态内存中,在程序开始运行前就会被分配,知道程序运行结束,该变量的内存地址也不会发生变化。在代码块外部定义的变量默认属于静态变量(也就是我们所说的全局变量,不过从定义上来说,全局应该包括了作用域存储类型两方面的意义)。如果要在代码块内定义静态变量,就需要使用static关键字。在一些小规模的代码块中(典型的比如一个循环),为了保持变量值不变,而又想要这个变量具有局部作用域,以不至于在其他地方被误操作,就应当使用静态局部变量。例子中的第8行就是一个静态变量的声明。

对于静态变量和自动变量,还需要指出的是他们初始化的差别。由于静态变量在程序编译链接的时候可以预测到内存地址,所以即使不显式地初始化,其值也是0,如第3行的变量c;而20和21行中定义的变量是automatic类型的,运行时由操作系统分配堆栈,堆栈中的数据没有经过清零,所以初值是不确定的,并且运行两次,两次都可能不一样。


总结static的用法[1]:在用于定义函数时,或者用于代码块外部的变量声明时,static用于修改链接属性,从默认的external改为internal,但标识符的存储类型和作用域不受影响;当在代码块内部的变量声明时,static用于修改变量的存储类型,从automatic改为static,其链接属性和作用域不受影响。

--------------------------------------------------------------------------------------------------------------------------

参考文献:[1]"C与指针", Kenneth A.Reek


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值