现在的位置: 首页 > 综合 > 正文

C/C++中涉及存储方式的关键字:auto,static,register,extern

2013年01月09日 ⁄ 综合 ⁄ 共 2319字 ⁄ 字号 评论关闭

auto关键字
auto对象和变量被存储在栈中,它的生命周期仅存在于它的声明所在的块(block)中。在块中定义的块如果不加其它的修饰符则都是auto类型的。auto关键字可以省去。auto对象和变量对外部模块都是不可见的。

static关键字
它是C,C++中都存在的关键字,它主要有三种使用方式,其中前两种只指在C语言中使用,第三种在C++中使用。
(1)局部静态变量
(2)外部静态变量/函数
(3)静态数据成员/成员函数
下面就这三种使用方式及区别

一、局部静态变量
与auto类型(普通)局部变量相比, static局部变量有三点不同:
1. 存储空间分配不同,auto类型分配在栈上,属于动态存储类别,占动态存储区空间,函数调用结束后自动释放;而static分配在静态存储区,在程序整个运行期间都不释放。两者之间的作用域相同,但生存期不同。
2. static局部变量在所处模块的初次运行时进行初始化工作,且只初始化一次。
3. 对于局部静态变量,如果不赋初值,编译期会自动赋初值0或空字符;而auto类型的初值是不确定的。(对于C++中的class对象例外,class的对象实例如果不初始化,则会自动调用默认构造函数,不管是否是static类型)
二、外部静态变量/函数
在C中static有了第二种含义:用来表示不能被其它文件访问的全局变量和函数。为了限制全局变量/函数的作用域,函数或变量前加static使得函数成为静态函数。但此处“static”的含义不是指存储方式,而是指对函数的作用域仅局限于本文件(所以又称内部函数)。注意此时,对于外部(全局)变量,不论是否有static限制,它的存储区域都是在静态存储区,生存期都是全局的。此时的static只是起作用域限制作用,限定作用域在本模块(文件)内部。使用内部函数的好处是:不同的人编写不同的函数时,不用担心自己定义的函数,是否会与其它文件中的函数同名。
三、静态数据成员/成员函数(C++特有)
C++重用了这个关键字,并赋予它与前面不同的第三种含义:表示属于一个类而不是属于此类的任何特定对象的变量和函数。这是与普通成员函数的最大区别,也是其应用所在。比如在对某一个类的对象进行计数时,计数生成多少个类的实例,就可以用到静态数据成员。在这里面,static既不是限定作用域的,也不是扩展生存期的作用,而是指示变量/函数在此类中的唯一性。这也是“属于一个类而不是属于此类的任何特定对象的变量和函数”的含义。因为它是对整个类来说是唯一的,因此不可能属于某一个实例对象的。(针对静态数据成员而言,成员函数不管是否是static,在内存中只有一个副本,普通成员函数调用时,需要传入this指针,static成员函数调用时,没有this指针)
注意:
不能将union成员声明为static的,然而,对于全局的匿名union,必须显式的声明为static。

register关键字
只有函数参数和局部变量可被声明为register。意思是,在可能的情况下,该变量被存储在CPU寄存器中。register变量和auto变量一样,它的生命周期只维持在它所声明的块中。编译器并不赞成程序员指定register变量。实际的情况是,编译器会根据全局优化的需要自动决定是否采用register类型。

extern关键字
extern用在声明语句中表示该对象或变量是在其它编译单元中(不能说是其它文件,因为有些文件,如头文件不是编译单元)定义的;如果用在定义语句中,表示该变量对外部可见。
注意extern与#include作用的区别:
例1,使用extern:
//out.h
int a = 10;

//out.cpp
#include "out.h"

//example.cpp
#include <iostream>
using namespace std;

extern int a;
int _tmain(int argc, _TCHAR* argv[])
{
cout<<"a="<<a<<endl;

system("pause");
return 0;
}
编译链接流程:
由于out.cpp文件引用了out.h文件,所以out.cpp文件的内容变成了int a =10;,编译时生成编译单元out.obj(out.o),其中定义了变量a。example.cpp文件中出现了对a的引用cout<<"a="<<a<<endl;,但该文件中没有a的定义(extern inta;只是一个声明),而且包含的头文件中也没有,但是由于有声明extern inta;,表明a是在其它编译单元中定义的,编译不出错。最后链接器在编译单元out.obj(out.o)中找到a的定义,建立连接关系,生成最后的exe文件。该工程中有两个编译单元,最后链接成一个exe文件。

例2,使用#include:
//out.h
int a = 20;

//example.cpp
#include "out.h"
#include <iostream>
using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{
cout<<"a="<<a<<endl;

system("pause");
return 0;
}
编译链接流程:
example.cpp文件中出现了对a的引用cout<<"a="<<a<<endl;,但该文件中没有a的定义,但是包含的头文件out.h中有,这样在编译之前,头文件out.h展开到example.cpp文件中,相当于example.cpp文件中定义了a(int a = 20;),编译成功。最后链接器链接编译单元生成最后的exe文件。该工程中只有一个编译单元,最后链接成一个exe文件。


抱歉!评论已关闭.