我们知道,变量是有数据类型的,比如int、char、double等等
除了数据类型,变量还有一个属性,称为“存储类别”。
存储类别标识变量放在内存中的那个地方。
我们可以通过C语言中的关键字来控制变量的存放区域。C语言共有 4 个关键字用来指明变量的存储类别:
auto(默认的)、static(静态的)、register(寄存器的)、extern(外部的)。
auto
auto 是默认的,所有的变量默认就是 auto 的,局部变量放在栈,全局变量放在全局数据区
static
static 声明的变量称为静态变量,不管它是全局的还是局部的,都存储在静态数据区(全局变量本来就存储在静态数据区,即使不加 static)。
特点:
静态数据区的数据在程序启动时就会初始化,直到程序运行结束;
对于代码块中的静态局部变量,即使代码块执行结束,也不会销毁。
静态数据区的变量只能初始化一次,以后只能改变它的值,不能再被初始化,即使有这样的语句,也无效。
举例:
int main ()
{
int result, i;
for(i = 1; i<=100; i++){
result = sum(i);
}
printf("1+2+3+...+99+100 = %d\n", result);
system("pause");
return 0;
}
int sum(int n){
// 也可以不赋初值 0,静态数据区的变量默认初始化为 0
static int result = 0;
result += n;
return result;
}
运行结果:
1+2+3+…+99+100 = 5050
分析:
我们在 sum() 中定义了一个静态局部变量 result,它存储在静态数据区,sum() 函数执行结束也不会销毁,下次调用继续有效。静态数据区的变量只能初始化一次,第一次调用 sum() 时已经对 result 进行了初始化,所以再次调用时就不会初始化了,也就是说 static int result = 0; 语句无效。
静态局部变量虽然存储在静态数据区,但是它的作用域仅限于定义它的代码块,sum() 中的 result 在函数外无效,与 main() 中的 result 不冲突,除了变量名一样,没有任何关系。
register
一般情况下,变量的值是存储在内存中的,CPU 每次使用数据都要从内存中读取。如果有一些变量使用非常频繁,从内存中读取就会消耗很多时间,例如for(i=0; i<1000; i++)中的变量i,执行这段代码,CPU 为了获得 i,会读取 1000 次内存。
为了解决这个问题,可以将使用频繁的变量放在CPU的通用寄存器
中,这样使用该变量时就不必访问内存
,直接从寄存器中读取,大大提高程序的运行效率。
不过寄存器的数量是有限的,通常是把使用最频繁的变量定义为 register 的。
关于寄存器变量有以下事项需要注意:
为寄存器变量分配寄存器是动态完成的,因此,只有局部变量和形式参数才能定义为寄存器变量。
局部变量定义为寄存器变量就不能再定义为静态变量,因为一个变量只能声明为一种存储类别。
寄存器的长度一般和机器的字长一致,只有较短的类型如 int、char、short 等才适合定义为寄存器变量,诸如 double 等较大的类型,不推荐将其定义为寄存器类型。
CPU的寄存器数目有限,即使定义了寄存器变量,编译器可能并不真正为其分配寄存器
相反,,即使没有使用 register 关键字,编译器也能自动识别使用频繁的变量,在有可用的寄存器时也自动为其分配寄存器,无须由程序员来指定。
extern
extern是一个关键字,它告诉编译器存在着一个变量或者一个函数,如果在当前编译语句的前面没有找到相应的变量或者函数,可以在当前文件的后面或者其它文件中找
#include <iostream>
using namespace std;
extern int i;
extern void func();
int _tmain(int argc, _TCHAR* argv[])//typedef wchar_t _TCHAR;#define _tmain wmain
{
i = 0;
func();
return 0;
}
int i;
void func()
{
i++;
cout << "i = " << i << endl;
}
上面代码中变量i和函数func在文件末尾定义,所以变量需要使用extern关键字告诉编译器,变量在别的地方定义。