从链接属性和存储类型,看static和extern关键字
来源:互联网 发布:铜仁学院大数据学院 编辑:程序博客网 时间:2024/04/28 15:16
在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
- 从链接属性和存储类型,看static和extern关键字
- c语言的链接属性和static、extern关键字
- extern和static关键字
- 关键字extern和static
- static和extern关键字
- 链接属性和存储类型
- 存储类型和static关键字作用小结
- 有关static和extern关键字
- C++ extern和static关键字
- 浅谈关键字static和extern
- const、static和extern关键字
- static和extern关键字介绍
- 从链接、存储的角度去理解编译器对关键字的处理(static、extern等)
- 关于c++static关键字和extern关键字
- 浅谈static关键字和extern关键字
- 存储说明符extern和static
- 作用域、链接属性和存储类型
- 优先级与链接属性。详解 static 与 extern 关键字。
- Android 清除缓存
- Linux下Tomcat配置为系统服务,并开机自启动
- MUI:全局变量、常量、共享数据、跨webview传参的综述
- 51nod 1015 水仙花数
- Spring Boot——2分钟构建spring web mvc REST风格HelloWorld
- 从链接属性和存储类型,看static和extern关键字
- 0day安全软件漏洞分析技术读书笔记-windows2000的堆的工作方式(上)
- 大数据Spark “蘑菇云”行动第72课: 基于Spark 2.0.1项目实现之二. 实战 各种小bug修复及性能调优 200并行度调整为2个task
- 1016 水仙花数 V2
- 类访问修饰符
- 161103
- 51nod 1018 排序
- RTTI在Java中的三种存在形式
- java日期转换