C和指针笔记 3.7 存储类型
变量的破碎类型是指存储变量值的内存类型。变量的存储类型决定变量何时创建、何时销毁以及它的值将保持多久。
有三个地方可以用于存在变量:普通内存、运行时堆栈、硬件寄存器。
变量的缺省存储类型取决于它的声明位置。凡是在任何代码块之外声明的变量问题存储于静态内存中,也就是不属于堆栈的内存,这类变量称为静态变量。对于这类变量,你无法为它们指定其他存储类型。静态变量在程序运行之前创建,在程序的整个执行期间始终存在。它始终保持原先的值,除非给它赋一个不同的值或者程序结束。
在代码块内部声明的变量的缺省存储类型是自动的,也就是说它存储于堆栈中,称为自动变量。有一个关键字auto就是用于修饰这种存储类型的,但它极少使用,因为代码块中的变量在缺省情况下就是自动变量。在程序执行到声明自动变量的代码块时,自动变量才被创建,当程序的执行流离开该代码块时,这些自动变量便自行销毁。
对于在代码块内部声明的变量,如果给它加上关键字static,可以使它的存储类型从自动变为静态。具有静态存储类型的变量在整个程序执行过程中一直存在,而不仅仅在声明它的代码块的执行时存在。注意,修改变量的存储类型并不表示修改该变量的作用域,它仍然只能在该代码块内部按名字访问。
函数的形式参数不能声明为静态,因为实参问题在堆栈中传递给函数,用于支持递归。
最后,关键字register可以用于自动变量的声明,提示它们应该存储于机器的硬件寄存器而不是内存中,这类变量称为寄存器变量。通常寄存器变量比存储于内存的变量访问起来效率更高。但是,编译器并不一定要理睬register关键字,如果有太多的变量被声明为register,它只能选取前几个实际存储于寄存器中,其余的就按普通自动变量处理。如果一个编译器自己具有一套寄存器优化方法,字也可能忽略register关键字,其依据是由编译器决定哪些变量存储于寄存器中比人脑的决定更为合理一些。
自动变量和静态变量的初始化存在一个重要的差别。在静态变量的初始化中,我们可以把可执行程序文件想要初始化的值放在当程序执行时变量交付使用的位置。当可执行文件载入到内存时,这个已经保存了正确初始值的位置将赋值给那个变量。完成这个任务并不需要额外的时间,也不需要额外的指令,变量将会得到正确的值。如果不显示地指定其初始值,静态变量将初始化为0.
自动变量的初始化需要更多的开销,因为当程序链接时还无法判断自动变量的存储位置。事实上,函数的局部变量在函数的每次调用中可能占据不同的位置。基于这个理由,自动变量没有缺省的初始值,而显式的初始化将在代码块的起始处插入一条隐式的赋值语句。
这个技艺造成4种后果。
1)自动变量的初始化较之赋值语句效率并无提高。除了声明为const的变量之外,在声明变量的同时进行初始化和先声明后赋值只有风格之差,并无效率之别。
2)这条隐式的赋值语句使自动变量在程序执行到它们所声明的函数(或代码块)时,每次都将重新初始化。这个行为与静态变量大不相同,后者只是在程序开始执行前初始化一次。
3)由于初始化在运行时执行,你可以用任何表达式作为初始化值,例如:
int func(int a)
{
int b = a + 3;
}
4)除非你对自动变量进行显式的初始化,否则当自动变量创建时,它们的值总是垃圾。