halo大家好~今天我们来分享一下在有关C语言面试中我们最常被面试官问到的static关键字到底有什么用?相信学完本期内容你就会回答了~
一、存储类别
首先我们来了解下存储类别。
从硬件方面看,每个变量存储的值都占用一定的物理内存空间,C语言中把这样一块内存称为对象。
从软件方面看,程序需要访问对象,可以通过声明变量来完成:
int entity = 3;
程序通过访问标识符entity去访问对象。
一般而言,那些指定对象的表达式称为左值,即entity即是标识符也是左值。如果可以使用左值改变对象中的值,该左值就是一个可修改的左值(modifiable value)。很简单吧,如果你理解不了,想象一下,我要将存储3的内存空间改成4怎么做?
entity = 4;
通过标识符entity(左值)去修改某一内存空间的值。
再看一个例子,声明:
const char *pc = “hello world!”;
字符串“hello world!”存放在一段连续的内存空间里,假设从地址0x56000000开始,那pc存放的值就是0x56000000,即pc的值存放了字符串的地址。
我们可以让pc重新指向其他字符串(改变pc里的值),所以标识符pc是个可修改的左值,const保证了被pc指向的字符串内容不被修改,但是无法保证pc不指向其他字符串。但是*pc不是可修改的左值,因为*pc指定了储存‘h’字符的数据对象。
可以用存储期描述对象,所谓存储期是指对象在内存中保留了多长时间。
标识符用于访问对象,使用作用域和链接描述标识符。
1.1 作用域
作用域描述程序中可访问标识符的区域。一个C变量的作用域可以是:
块作用域、函数作用域、函数原型作用域或文件作用域。
块就是一对用花括号{}括起来的代码区域,我们使用的局部变量、函数的形参都具有块作用域。C99把块的概念拓展到包括for循环、while循环,例如:
for(int i=0;i<5;i++);
变量i的作用域也是块作用域,一旦循环结束,就不能再访问i。
函数作用域(function scope)仅用于goto语句的标签。这意味着即使一 个标签首次出现在函数的内层块中,它的作用域也延伸至整个函数。如果在 两个块中使用相同的标签会很混乱,标签的函数作用域防止了这样的事情发 生。
函数原型作用域的范围是从形参定义处到原型声明结束。这意味着,编 译器在处理函数原型中的形参时只关心它的类型,而形参名(如果有的话) 通常无关紧要。而且,即使有形参名,也不必与函数定义中的形参名相匹 配。只有在变长数组中,形参名才有用。
变量的定义在函数的外面,具有文件作用域(file scope)。具有文件作 用域的变量,从它的定义处到该定义所在文件的末尾均可见。定义在函数体外,这样的变量可用于多个函数,所以文件作用域变量也称为全局变量(global variable)。
所以,局部变量具有块作用域,全局变量具有文件作用域。
1.2 链接
说到链接,首先我们要知道C变量具有3种链接属性:外部链接、内部链接和无链接。
C预处理时,用包含的头文件内容替换#include指令,编译器源代码文件和所有的头文件都看成是一个包含信息的单独文件。这个文件被称为翻译单元 (translation unit)。
具有块作用域、函数作用域或函数原型作用域的变量都是无链接变量。
具有文件作用域的变量可以是外部链接或内部链接。
外部链接变量可以在多文件程序中使用,内部链接变量只能在一个翻译单元中使用(即一个源代码文件和它所包含的头文件)。
但是,对程序员而言这些术语太长了。一 些程序员把“内部链接的文件作用域”简称为“文件作用域”,把“外部链接的文件作用域”简称为“全局作用域”或“程序作用域”。
那么如何知道文件作用域是内部链接还是外部链接呢?就看外部定义中有没有static!举个例子:
int i = 6; //文件作用域,外部链接 static int k = 6; //文件作用域,内部链接 int main(void) { ... }
该文件和同一程序的其他文件都可以使用变量i。而变量k属文件私有,该文件中的任意函数都可使用它。
总结:当你的Project里有多个C文件的时候,编译器编译它们的时候所有文件都能使用变量i,而加了static的全局变量k,则只有该文件可以使用,其他文件是看不到变量k的。
1.3 存储期
C对象有4种存储期:静态存储期、线程存储期、自动存储期、动态分配存储期。
静态存储期:如果对象具有静态存储期,那么它在程序的执行期间一直存在。文件作用域变量具有静态存储期。注意:static仅仅是声明了它的链接属性,而无论是外部连接还是内部连接,所有的文件作用域都具有静态存储期。
线程存储期用于并发程序设计,程序执行可被分为多个线程。具有线程 存储期的对象,从被声明时到线程结束一直存在。以关键字_Thread_local声 明一个对象时,每个线程都获得该变量的私有备份。
块作用域的变量通常都具有自动存储期。当程序进入定义这些变量的块时,为这些变量分配内存;当退出这个块时,释放刚才为变量分配的内存。我们到目前为止使用的局部变量都是自动类别。
注意:块作用域变量也能具有静态存储期。为了创建这样的变量,要把变量声明在块中,且在声明前面加上关键字static。
总的来说:static关键字的作用就是限制作用域和存储期。通常面试官还会跟全局变量和局部变量一起问的哦~
号主:一枚机械专业本科生,经历了转行,从外包逆袭到芯片原厂的Linux驱动开发工程师,深入操作系统的世界,贯彻终身学习、终身成长的理念。平时喜欢折腾,寒冬之下,抱团取暖,期待你来一起探讨技术、搞自媒体副业,程序员接单和投资理财。【对了,不定期送闲置开发板、书籍、键盘等等】。
如果你想了解我的转行经验,欢迎找我交流~gongzhong号【哆哆jarvis】
一起不断探索自我、走出迷茫、找到热爱,希望和你成为朋友,一起成长~