注:本文参照 做学习总结。
static关键字在C、C++中主要有以下三种使用方式:
1、局部静态变量
2、外部静态变量/函数
3、静态数据成员/成员函数
其中,前两种在C/C++语言中使用,第三种只在C++中使用。下面详细分析。
一、局部静态变量
在C/C++中,局部变量按照存储形式可分为三种:auto, static, register。
auto类型(普通)局部变量与static局部变量相比:
1、存储空间分配、作用域、生存期
auto类型分配在栈上,属于动态存储类别,占动态存储区空间,作用域仅仅限于声明该变量的函数内部。函数调用结束后自动释放,生命期不过是在声明该变量的函数内部。
static类型分配在静态存储区,作用域仅仅限于声明该变量的函数内部。在程序整个运行期间都不释放,生命期贯穿于程序运行的整个过程。
2、赋初值的处理方式
auto自动变量赋初值是在函数调用时进行,每调用一次函数重新给一次初值,相当于执行一次赋值语句。
static静态局部变量在编译时赋初值,即只赋初值一次。
3、未赋初值时的处理方式
如果在定义局部变量时不赋初值的话:
对于auto局部变量,它会是一个不确定的值。
对于static局部变量,在编译期会自动赋初值0或空字符。
另外,对于C++中的class对象例外,class的对象实例如果不初始化,会自动调用默认构造函数,不管是否是static类型。
特点:static局部变量的“记忆性”与生命期的“全局性”
所谓记忆性是指在两次函数调用时,在第二次调用进入时,能保持第一次调用退出时的值。
注意:
1、“记忆性”,程序运行很重要的一点就是可重复性,而static变量的“记忆性”破坏了这种可重复性,造成不同时刻运行的结果可能不同。
2、“生存期”全局性和唯一性。普通的local变量的存储空间分配在stack上,因此每次调用函数时,分配的空间都可能不一样,而static具有全局唯一性的特点,每次调用时,都指向同一块内存。
3、在多线程和递归中需要注意这个问题。
二、外部静态变量/函数
在C语言中static还用来声明静态外部全局变量,那么这个全局变量的作用域就被限制在本文件内部。
外部变量(即全局变量)是在函数的外部定义的,它的作用域为从变量定义处开始,到本程序文件的末尾。如果外部变量不在文件的开头定义,其有效的作用范围只限于定义处到文件终了。如果在定义点之前的函数想引用该外部变量,则应该在引用之前用关键字extern对变量作“外部变量声明”。表示该变量是一个已经定义的外部变量。有了此声明,就可以从“声明”处起,合法地使用该外部变量。
如果我们声明的全局变量不想被其他文件访问和使用又该怎么办?那就在声明的时候,在该全局变量前面加上个关键字static。
在C语言中我们的函数默认都是全局的,也就是说你可以调用其他文件中的函数。在使用的时候,我们像前面一样在头文件中加上extern就可以了。但是有时候我们写的函数并不想让别的文件访问和调用,那么我们在声明的时候前面加上static就可以了。
使用内部函数的好处有二:
1、可以让内部函数不为人所能用,而仅仅让调用者使用他能使用的东西,有利于保护代码。
2、不同的人编写不同的函数时,不用担心自己定义的函数,是否与其他文件中的函数同名。
三、静态数据成员/成员函数(C++特有)
C++重用了这个关键字,并赋予它与前面的不用的第三种含义:表示属于一个类而不是此类的任何特定对象的变量和函数。这与普通成员函数的最大区别,也是其应用所在。比如在对某一个类的对象进行计数时,计数生成多少个类的实例,就可以用到静态数据成员。在这里面,static既不是限定作用域的,也不是扩展生存期的作用,而是指示变量/函数在此类中的唯一性。这也是“属于一个类而不是属于此类的任何特定对象的变量和函数”的含义。因为它是对整个类来说是唯一的,因此不可能属于某一个实例对象的。(针对静态数据成员而言,成员函数不管是否是static,在内存中只有一个副本,普通成员函数调用时,需要传入this指针,static成员函数调用时,没有this指针。)