变量类型,作用域,存储空间与生命周期
变量的作用域:指变量能够在什么地方被访问。比如有的变量只能在函数内部访问,有的变量是所有函数都能访问。
变量的存储空间:存放变量的内存位置。要明白变量在内存中存放的位置,首先就先了解下系统的内存布局。
以x86为例,x86支持32位寻址,因此可以支持最大232=4GB的虚拟内存空间(也可以通过PAE技术增加到36位寻址,因此可以将寻址空间扩大到64GB)。如图所示,在
X64(AMD64)的内存布局与X86的内存布局类似,不同的地方在于各自空间的范围和大小不同,同时X64下还存在着一些空洞(hole),如图所示。在X64内存理论上支持最大264的寻址空间,但实际上这个空间太大了,目前根本用不完,因此实际上的X64系统一般都只支持到40多位(比如Windows支持44位最大寻址空间为16TB,Linux 支持48位最大寻址空间256TB等),支持的空间达到了TB级别。但是,无论是在内核空间还是在应用层空间,这些上TB的空间并不都是可用的,存在着所谓的空洞。
当程序加载入内存后,程序在内存中可以分为若干个区,这些区包括:静态区(.data,.rdata,.bss段等),代码区(.text),堆区,栈区等。
.text 代码段,这个存放代码的,用汇编角度来看就是指令。
.rdata 只读数据段,存放常量,字符常量,const常量。
.data 数据段,存放已经初始化好的全局变量和静态变量。
.bss 存放未初始化的全局变量和静态变量。
.rdata,.data,.bss都是存放的数据。除了.bss段,.rdata,.data段的值都是在编译的时候就确定了,并且将其编译进了可执行文件,经过反汇编都能找得到。bss段是在代码运行的时候手动编写汇编代码将其初始化为0的(这就是未初始化的全局和静态变量默认值为0的根源)
.stack:栈区,存放局部变量等。如下图所示,栈区存放这函数调用过程中的形参,返回地址以及局部变量等(将在函数一章讲调用约定的时候具体介绍栈上的数据)。
变量的生命周期:变量有效的时间段,只有在变量的生命周期内,才能访问该变量。有的变量的生命周期是函数运行期间,函数结束,变量就消失了。有的变量的生命周期是程序运行期间,只要程序还未结束,变量就不会消失或销毁。
变量分类:全局变量,局部变量,静态变量(静态全局变量和静态局部变量),寄存器变量,外部变量。
全局变量:全局变量的说明的位置在所有函数之外 ,整个程序可见,生命周期为整个程序运行期间,存储位置为静态存储区。
局部变量:在函数内部说明的变量为局部变量,只有在函数执行时,局部变量才存在,当函数执行完退出后,局部变量随之消失。作用域为函数内部,存储空间为栈。
全局静态变量:与全局变量唯一不同的地方是别的文件不能访问该变量
局部静态变量:与局部变量的区别是,存储在静态区,整个程序运行期间有效,具有记忆功能,只初始化一次,默认初始化为零
寄存器变量:不像其他变量那样在内存中存放数据,而是在CPU的寄存器中暂存数据,使用寄存器变量比使用内存变量的操作速度快得多。只有整型和字符型变量可定义为寄存器变量。由于CPU中寄存器有限,尽量减少使用数量和和占用时间,用完马上释放;不能定义为全局变量,也不能定义在结构或者类中。
extern关键字:为了解决全局变量和函数的共用问题,就引入了 extern关键字。这样只需在一个文件中定义全局变量和函数,在另一个文件中要用到这些变量和函数时,只需将那个文件中的变量和函数说明表复制过来,在前面加上extern,告诉编译器,这些变量和函数已经在别的文件中定义说明。
//main.cpp
int a = 0; //全局变量
char *p1; //全局变量
static int x=10; //全局静态变量,10为常量
void func(void)
{
int b; //局部变量
char s[] = “
char *p2; //p2为局部变量
char *p3 = “hello, world”; //p3为局部变量,”hello,
world”为常量
static int c =0;//局部静态变量
register int i =0;//寄存器变量
p1 = (char *)malloc(128); //p1指向堆上的内存,直到free
p2 = (char *)malloc(256);//p2指向对上的内存,直到free
free(p1);
free(p2);
}
int main(void)
{
func();
printf(“hello world\n”);
return 0;
}
归纳起来,不同类型变量的存储空间,作用域与生命周期如下表所示:
变量类型 |
存储空间 |
作用域 |
声明周期 |
全局变量 |
静态区(.data存放初始化全局变量,.bss存放未初始化全局变量) |
整个程序 |
程序运行期间 |
全局静态变量 |
静态区(.data存放初始化全局变量,.bss存放未初始化全局变量) |
当前源文件 |
程序运行期间 |
局部变量 |
栈 |
当前函数内部 |
函数执行期间 |
局部静态变量 |
静态区 |
当前函数内部,只初始化一次 |
程序运行期间 |
寄存器变量 |
寄存器 |
当前函数 |
函数运行期间 |