12. 全局静态变量和局部静态变量

静态全局变量和静态局部变量的探索

一、静态全局变量

1.特点

静态全局变量具有文件作用域,生命期是所处模块装载到所处模块卸载,处于同一文件中的代码能直接访问它,外部文件不能直接访问。假设写了如下代码,编译通过。

 

现在在同一工程下新建文件,输入如下代码,编译通过,链接失败。

 

 

如果换成全局变量,则编译连接成功:

 

 

由此可见,在用extern定义变量时,只能在本文件使用,其他文件无法直接访问。

2.机制

静态全局变量本质上是受编译器按语法约束的全局变量,如果未初始化,则分配在数据区的未初始化去,如果已初始化,则分配在数据区的已初始化区域。

 

 

可以观察到已初始化的静态全局变量和全局变量地址紧邻,未初始化的静态全局变量和全局变量地址紧邻。已初始化的全局变量和未初始化的全局变量之间有一定差距。

3.适用场合

某些数据或函数不想被外部文件访问时,可定义为静态全局变量。好处是提供了一定程度的封装,高内聚、低耦合、分责任。

二、静态局部变量

1.特点

静态局部变量只能在定义所在作用域内访问,具有块作用域,生命期是所处模块装载到所处模块卸载。

假设写了如下代码,编译无法通过,报错“error C2065: “nTest1”: 未声明的标识符”:

 

2.机制

2.1初始化为常量时

写如下代码,可以发现静态全局变量,静态局部变量,全局变量的地址紧邻。

 

 

2.2初始为变量时

C文件中,编译不通过:

 

 

cpp文件可编译通过(使用VC6)

 

第一次给nTest1赋值时,00427E50处变为1

 

单步一次,变为00427E50处变为3

 

再单步一次,变为07

 

推测每一个bit保存局部静态变量是否初始化,为0则表示未初始化,1表示已初始化,所以运行时访问此bit时,为1则跳过初始赋值代码。

照此推测,修改为0,应该会再次赋值:

 

单步,发现确实修改了

 

 

继续单步

 

继续单步

 

照此推测,将00427E50处改为5,则00427E58处会被赋值,其余两处不会。先手动修改:

 

单步一次:

 

单步两次:

 

单步三次:

 

符合推测,所以vc6编译器用一个bit保存局部静态变量是否初始化,为0则表示未初始化,1表示已初始化。

2.3 编译器如何控制它跨界访问

c文件中定义static_ABC的局部静态变量,更改调用约定,参数,返回值,每次改一个。再去main.obj里搜索static_ABC,发现均无变化,在static_ABC周围加上花括号,则有变化。

?static_ABC@?3??Foo1@@9@9 2层花括号,函数名Foo1

?static_ABC@?2??Foo1@@9@9 1层花括号

?static_ABC@?1??Foo1@@9@9 无额外层花括号

?static_ABC@?3??Foo2@@9@9 2层花括号,函数名2

?static_ABC@?2??Foo2@@9@9 1层花括号

?static_ABC@?1??Foo2@@9@9 无额外层花括号

cpp文件中则和返回类型,参数类型,参数个数,调用约定均有关联。表现如下:

//?static_ABC@?1??Foo1@@YAXXZ@4HA

//?static_ABC@?2??Foo1@@YAXXZ@4HA

//?static_ABC@?3??Foo1@@YAXXZ@4HA

//?static_ABC@?3??Foo1@@YAXH@Z@4HA

//?static_ABC@?3??Foo1@@YAXHH@Z@4HA

//?static_ABC@?3??Foo1@@YAXHHH@Z@4HA

//?static_ABC@?3??Foo1@@YAHHHH@Z@4HA

//?static_ABC@?3??Foo1@@YANHHH@Z@4HA

//?static_ABC@?3??Foo1@@YGNHHH@Z@4HA

//?static_ABC@?3??Foo1@@YINHHH@Z@4HA

//?static_ABC@?3??Foo1@@YANHHHZZ@4HA

猜你喜欢

转载自www.cnblogs.com/Nutshelln/p/12715525.html