在C和C++中static的作用如下:
(1)static修饰的局部变量(静态局部变量)存储期等于程序执行周期(所以无论调用几次都只能初始化一次)。
(2)static修饰的全局变量(静态外部变量)只能在本文件(程序单元)中访问,不能在其它文件中访问,即便用extern声明。
(3)static修饰的函数只能在本文件(程序单元)中调用,不能被其他文件调用,即便用extern声明。
变量存储类别 | 函数内 | 函数外 | |||
作用域 | 存储期 | 作用域 | 存储期 | ||
局部变量 | 自动变量(动态局部变量) | YES | YES | NO | NO |
局部变量(静态局部变量) | YES | YES | NO | YES | |
全局变量 | 静态外部变量 | YES | YES | YES(仅限本文件内) | YES |
外部变量(非静态外部变量) | YES | YES | YES | YES |
PS. Static修饰的局部变量存放在全局数据区的静态变量区。初始化的时候默认初始化为0。
问题来了:什么时候可以使用static修饰?
(1)函数调用完希望保留局部变量值的时候。
(2)局部变量初始化后在函数内不需要改变变量值的时候(不必每次调用时重复初始化+赋值)。
(3)一般来说,程序应该忌用全局变量(内存占用、通用性等),慎用静态局部变量(内存占用等)。所以发现需要使用全局变量时应该先考虑是否能使用static来替代。
在C++中static关键字还有在类中的使用:
在类中,如果希望各对象中的数据成员的值是一样的,可以用static修饰静态数据成员来实现。
静态数据成员
(1)静态数据成员属于类的静态成员,而不是对象成员。 因此静态数据成员可以实现多个对象之间的数据共享,在内存中只占一份空间,如果改变它的值,则各对象中这个数据成员的值都被改变。
(2)静态数据成员是在程序开始运行时被分配空间,到程序结束之后才释放(而不是随对象建立而分配空间,撤销而释放空间)。只要类中指定了静态数据成员,即使不定义对象,也会为静态数据成员分配空间。
(3)静态数据成员可以被初始化,但是只能在类体外进行初始化,若为对静态数据成员赋初值,则编译器会自动为其初始化为0 。
(4)静态数据成员既可以通过对象名引用,也可以通过类名引用。
静态成员函数
(1)静态成员函数的作用是用来访问静态数据成员。
(2)非静态成员函数有this指针,而静态成员函数没有this指针。 因此,
(3)静态成员函数不能默认地访问非静态成员。
(4)静态成员函数属于类的静态成员,而不是对象成员。
对静态和static的理解:
只有在静态局部变量和静态数据成员中,静态才是“静态存储方式”中静态的意思。
static修饰的全局变量(静态外部变量)没有这个意思,因为全局变量本来就是静态存储的,(非静态)外部变量也是静态存储。
static修饰的静态成员函数也没有这个意思,它不过是为了对应静态数据成员,少了个this指针而已。
static修饰的普通函数更没有这个意思(函数不谈什么静态动态)。
最后:一个笔记:
补充一句,有的时候书上说全局变量的作用域是整个程序,而不是下图说的程序单元(源文件),其实并不矛盾。不用static声明的话,全局变量默认就是(非静态)外部变量。由于组成一个程序的每个编译单元/程序单元在各自编译完成后,都要链接在一起,所以在函数外定义的全局变量作用域的的确确是整个程序。尝试在两个源文件都声明int a;试图生成解决方案的时候就会报错“多重定义”。
但是,编译过程是每个编译单元单独进行的。所以,如果不(在其他程序单元中)用extern声明(定义在本程序单元中的)全局变量的话,相应的其他程序单元的编译将无法完成。因此,如果不使用extern,全局变量的作用域被硬生生“缩减”为全局变量所在的程序单元,而非整个程序。下图提到“全局变量的作用域”处还没有讲到extern声明的使用,作用域当然仅仅是本程序单元/编译单元。
PS. 如果编译不以文件为单位,而是整个程序一起编译。全局变量的作用域自然是整个程序,而若程序中所有文件一起编译,文件实际上也只是出于美观的分页需要,并没有任何实际作用了。