1. C语言中的 static
在C语言中,从变量的作用域(空间)角度来分,可以分为全局变量和局部变量;从变量值存在的时间(生存期)来分,有动态存储和静态存储两种类型,静态存储时程序整个运行时间都存在,而动态存储则是在调用函数时临时分配单元。
我们来看在 static 关键字修饰之前,全局变量和局部变量的作用域和生存期是怎样的?
extern.cpp
int g_variable = 0;
main.cpp
#include <iostream>
using namespace std;
extern int g_variable;
void Function()
{
int variable = 0;
++variable;
++g_variable;
}
int main()
{
++variable;
++g_variable;
return 0;
}
编译代码 //error C2065: 'variable' : undeclared identifiermain.cpp
16
错误是显然的,说明局部变量variable的作用域仅限于函数Function,删除16行 ++variable;编译通过,说明全局变量g_variable的作用域是整个源程序,不过对于全局变量不在其定义的源文件中使用时需要用到 C++ 关键字 extern。
修改 main.cpp
#include <iostream>
using namespace std;
extern int g_variable;
void Function()
{
int variable = 0;
cout<<"variable: "<<variable<<endl;
cout<<"g_variable: "<<g_variable<<endl;
++variable;
++g_variable;
}
int main()
{
for (int i=0; i<3; i++)
{
Function();
}
return 0;
}
WindowXP+VS2008下 运行结果输出:variable: 0
g_variable: 0
variable: 0
g_variable: 1
variable: 0
g_variable: 2
可见
variable每次输出结果都是0(第一次初始化的值),而g_variable值一直都在增加,说明局部变量variable在每次函数Function调用完之后,就被释放掉了,而全局变量g_variable则在程序运行期间一直存在,由此我们总结:在没有static关键字修饰情况下,全局变量的作用域是整个源程序,而局部变量的作用域是其定义的那个函数或语句内,全局变量的生存期是整个程序执行期,而局部变量则是在其所在函数调用结束后释放。
那么在 static 关键字修饰之后,全局变量和局部变量的作用域和生存期又是怎样的呢?
extern.cpp
static int g_variable = 0;
main.cpp
#include <iostream>
using namespace std;
extern int g_variable;
void Function()
{
static int variable = 0;
++variable;
++g_variable;
}
int main()
{
++variable;
++g_variable;
return 0;
}
编译代码 //error C2065: 'variable' : undeclared identifiermain.cpp 16 错误是显然的,说明static局部变量variable的作用域仅限于函数Function,修饰后作用域并没有变化。
删除16行 ++variable;编译代码,还是出现
错误
,不过这次是链接错误
//error LNK2001: unresolved external symbol "int g_variable" (?g_variable@@3HA) main.obj
找不到外部全局变量g_variable,原因是因为全局变量g_variable有了static修饰之后,作用域发生了变化,原先作用于整个源程序的全局变量g_variable作用域现在被限制在了extern.cpp内,所以在main.cpp里找不到。删除extern.cpp,修改main.cpp
#include <iostream>
using namespace std;
static int g_variable = 0;
void Function()
{
static int variable = 0;
cout<<"variable: "<<variable<<endl;
cout<<"g_variable: "<<g_variable<<endl;
++variable;
++g_variable;
}
int main()
{
for (int i=0; i<3; i++)
{
Function();
}
return 0;
}
WindowXP+VS2008下 运行结果输出:variable: 0
g_variable: 0
variable: 1
g_variable: 1
variable: 2
g_variable: 2
我们可以看到 variable和g_variable在函数Function连续不断地调用下一直增加,可见在static修饰之后,局部变量的生存期发生了变化,在程序运行期间一直存在,而全局变量g_variable生存期没变,在程序运行期间一直存在,由此我们总结:在有了static关键字修饰情况下,全局变量的作用域被限制在整个源文件内,而局部变量的作用域没变,仍旧是其定义的那个函数或语句内,全局变量的生存期是整个程序执行期,而局部变量的生存期也改变为整个程序执行期。
我们应该明白 static 关键字的作用了,也清楚 局部变量、static局部变量、全局变量、static全局变量是什么个情况了(作用域和生存期),可是为什么是这样呢?
内存中用户使用的存储空间可分为3个部分:程序区、静态存储区、动态存储区;数据分别放在静态存储区和动态存储区中,
全部的
全局变量和 static局部变量存放在静态存储区中,在程序开始执行是给全局变量分配存储区,程序执行完毕就释放。在程序执行过程中它们占据固定的存储单元,而不是动态地进行分配和释放。而对于普通的局部变量(没有static修饰)和函数形参等则存放在动态存储区中,它们在函数调用开始时动态分配存储空间,函数结束时释放这些空间。在程序执行过程中,这种分配和释放是动态的,如果在一个程序中两次调用同一函数,而在此函数中定义了普通的局部变量,在两次调用时分配给这些局部变量的存储空间的地址可能是不相同的。——摘自《C语言程序设计》
最后用表格梳理一下 局部变量、static局部变量、全局变量、static全局变量 的作用域和生存期:
| 作用域 | 生存期 |
局部变量 | 定义的函数或语句内 | 从定义到定义的函数或语句结束 |
static局部变量 | 定义的函数或语句内 | 整个程序运行期 |
全局变量 | 整个源程序 | 整个程序运行期 |
static全局变量 | 定义的文件中 | 整个程序运行期 |