C++变量属性
一个变量除了数据类型以外,还有3种属性:
存储类别 C++允许使用auto,static,register和extern 4种存储类别。
作用域 指程序中可以引用该变量的区域。
存储期 指变量在内存的存储期限。
存储类别指的是数据在内存中存储的方法。存储方法分为静态存储和动态存储两大类。
C++ 程序中变量的存储类别:
自动的(auto)、静态的(static)、寄存器的(register)和外部的(extern)
内存存储空间可以分为三部分,即:程序区、静态存储区、动态存储区
数据分别存放在静态存储区和动态存储区中。全局变量全部存放在静态存储区中,在程序开始执行时给全局变量分配存储单元,程序执行完毕就释放这些空间。在程序执行过程中它们占据固定的存储单元,而不是动态地进行分配和释放。
在动态存储区中存放以下数据:
函数形式参数。在调用函数时给形参分配存储空间。
函数中的自动变量(未加static声明的局部变量)。
函数调用时的现场保护和返回地址等。
auto:
函数中的局部变量,如果不用关键字static加以声明,编译系统对它们是动态地分配存储空间的。函数的形参和在函数中定义的变量(包括在复合语句中定义的变量)都属此类。在调用该函数时,系统给形参和函数中定义的变量分配存储空间,数据存储在动态存储区中。在函数调用结束时就自动释放这些空间。如果是在复合语句中定义的变量,则在变量定义时分配存储空间,在复合语句结束时自动释放空间。此这类局部变量称为自动变量(auto variable)。自动变量用关键字auto作存储类别的声明。
//根据初始化表达式自动推断被声明的变量的类型
void AUTOTest(){
auto num = 1;//可直接写成 int num=1; 默认动态地分配存储空间
}
static:
有时希望函数中的局部变量的值在函数调用结束后不消失而保留原值,即其占用的存储单元不释放,在下一次该函数调用时,该变量保留上一次函数调用结束时的值。这时就应该指定该局部变量为静态局部变量。
void StaticTest() {
static int staticInt = 3;
staticInt++;
cout << staticInt << endl;
}
调用时:
int main(){
StaticTest();
StaticTest();
StaticTest();
StaticTest();
//函数中变量添加static输出结果为:4,5,6,7
//不添加static 输出结果为4,4,4,4,
}
对静态局部变量的说明:
静态局部变量在静态存储区内分配存储单元。在程序整个运行期间都不释放。而自动变量(即动态局部变量)属于动态存储类别,存储在动态存储区空间(而不是静态存储区空间),函数调用结束后即释放。
为静态局部变量赋初值是在编译时进行值的,即只赋初值一次,在程序运行时它已有初值。以后每次调用函数时不再重新赋初值而只是保留上次函数调用结束时的值。而为自动变量赋初值,不是在编译时进行的,而是在函数调用时进行,每调用一次函数重新给一次初值,相当于执行一次赋值语句。
如果在定义局部变量时不赋初值的话,对静态局部变量来说,编译时自动赋初值0(对数值型变量)或空字符(对字符型变量)。而对自动变量来说,如果不赋初值,则它的值是一个不确定的值。这是由于每次函数调用结束后存储单元已释放,下次调用时又重新另分配存储单元,而所分配的单元中的值是不确定的。
虽然静态局部变量在函数调用结束后仍然存在,但其他函数是不能引用它的,也就是说,在其他函数中它是“不可见”的。
静态存储要多占内存,而且降低了程序的可读性,当调用次数多时往往弄不清静态局部变量的当前值是什么。因此,如不必要,不要多用静态局部变量。
register 寄存器变量
一般情况下,变量的值是存放在内存中的。当程序中用到哪一个变量的值时,由控制器发出指令将内存中该变量的值送到CPU中的运算器。经过运算器进行运算,如果需要存数,再从运算器将数据送到内存存放。
为提高执行效率,C++允许将局部变量的值放在CPU中的寄存器中,需要用时直接从寄存器取出参加运算,不必再到内存中去存取。这种变量叫做寄存器变量,用关键字register作声明。
定义寄存器变量需要在数据类型前声明register类型即:
void RegisterTest() {
register int i = 1;
}
extern 外部变量
extern存储类用于提供一个全局变量的引用,全局变量对所有的程序文件都是可见的。当使用 'extern' 时,对于未初始化的变量,会把变量名指向一个之前定义过的存储位置。
当有多个文件且定义了一个可以在其他文件中使用的全局变量或函数时,可以在其他文件中使用extern来得到已定义的变量或函数的引用。extern是用来在另一个文件中声明一个全局变量或函数。
extern 修饰符通常用于当有两个或多个文件共享相同的全局变量或函数的时候。
例:
在test1.cpp中定义:
#include<iostream>
using namespace std;
int localNum;
extern void externFunc();
int main() {
localNum = 5;
externFunc(); //localNum is 5
//当执行此函数时,因为此函数在当前脚本中未经定义(声明为extern时不能再重复定义),程序会//从其他文件中找到相同名字的函数,并使用。
//externFunc()函数在test2.cpp中有定义
return 0;
}
在test2.cpp中定义:
#include<iostream>
using namespace std;
extern int localNum ;
//在使用此变量的时候,因为定义的为extern(定义为extern类型时,变量不能有初始值),脚本会从其他文件中查找该相同名字的变量,并使用。
void externFunc(void) {
cout << "localNum is " << externNum << endl;
}
在test1.cpp中定义了一个全局变量a,但它用static声明,因此只能用于本文件,虽然 在cpp文件中用了“extern int a;”,但test2.cpp文件中仍然无法使用test1.cpp中的全局变量a。
这种加上static声明、只能用于本文件的外部变量(全局变量)称为静态外部变量。如果已知道其他文件不需要引用本文件的全局变量,可以对本文件中的全局变量都加上static,成为静态外部变量,以免被其他文件误用。
需要指出,不要误认为用static声明的外部变量才采用静态存储方式(存放在静态存储区中),而不加static的是动态存储(存放在动态存储区)。实际上,两种形式的外部变量都用静态存储方式,只是作用范围不同而已,都是在编译时分配内存的。