auto、register、static、extern等存储类修饰符的区别 - [C/C++编程]

来源:互联网 发布:windows系统属于 编辑:程序博客网 时间:2024/05/19 17:09
转载时请以超链接形式标明文章原始出处和作者信息及本声明
http://kimva.blogbus.com/logs/19329180.html

一、标识符的链接(linkage)

(1)外部链接
表示在整个程序中(多个程序文件)是相同的函数或对象。常见的有,在函数体外声明的extern变量。
(2)内部链接
表示只在当前程序文件中是相同的函数或对象。其它程序文件不能对其进行访问。常见的有,在函数体外声明的static变量。
(3)无链接
一般声明在函数内部的auto、register变量、还有函数的参数,都是无链接。它的作用域是函数内部。

二、对象的生存周期(lifetime)
(1)静态生存周期
具有静态生存周期的所有对象,都是在程序开始执行之前就被事先创建和初始化。它们的寿命覆盖整个程序的执行过程。如在函数内定义了一个static变量,那第一次调用该函数后,该变量的值将会被保留,当第二次被调用时,该变量的值还是第一次调用结束时的值。
(2)自动生存周期
自动生存周期的对象的寿命由“对象定义所处在的大括号{}”决定。每次程序执行流进入一个语句块,此语句块自动生存周期的对象就会被创建一个新实例,同时被初始化。

三、存储类修饰符
(1)auto
auto修饰符只能用在函数内的对象声明。声明中有auto修饰符的对象具有自动生存周期。
在ANSI C中,函数内的对象声明在默认情况下有自动生存周期,所以在函数内声明时auto可省略。

(2)register
当声明对象有自动生存周期时,可以使用register修饰符。因此,register也只能用在函数内的声明中。
此关键字告诉编译器:此对象的存取应该尽量快,最好存储在CPU的寄存器中。然而,编译器不见得会这么做。
另外要注意的是,当一个对象声明为register,就不可使用地址运算符&了,因为它有可能被放到寄存器中。

(3)static
函数标识符如果被声明为static,就具有静态生命周期。
如果是定义在函数外,那么该对象具有内部链接,其它程序文件不能对其访问。
如果是定义在函数内,那么该对象具有无链接,函数外不能对其访问。
注意:static变量初始化时,只能用常量。

(4)extern
如果声明在函数外,那么该对象具有外部链接,能够在其它程序文件使用。但要注意它有可能会被函数内定义的重名的变量所隐藏起来。
如果声明在函数内,该对象具有何种链接取决于当前程序文件中定义在函数外的相同名字的对象。如果在函数外也定义了一下相同名字的static对象,则该函数内的对象具有无链接,否则具有外部链接。
extern的对象都具有静态生命周期。
使用extern时,注意不能重复定义,否则编译报错,如:
程序文件一:
extern int a = 10; //编译警告,extern的变量最好不要初始化
程序文件二:
extern int a = 20; //重复定义,应改为extern int a;
一般最好这样,如果需要初始化,可把extern修饰符去掉(但也不要重复定义),另外如果其它程序文件也需要用到该变量,可用extern来声明该变量。这样会比较清晰。

(5)缺
省修饰符
函数内,与auto相同;
函数外,与extern相同;



linkagelifetimeauto函数内no linkage自动函数外语法错语法错register函数内no linkage自动函数外语法错语法错缺省函数内no linkage自动函数外external linkage静态static函数内no linkage静态函数外internal linkage静态extern函数内与它在函数外所声明的一致静态函数外external linkage静态

例子:
int func1(void); //func1具有外部链接;
int a = 10; //a具有外部链接,静态生存周期;
extern int b = 1; //b具有外部链接,静态生存周期。但编译会有警告extern变量不应初始化,同时也要注意是否会重复定义;
static int c; //c具有内部链接,静态生存周期;
static int e; //e具有内部链接,静态生存周期;
static void func2(int d){ //func2具有内部链接;参数d具有无链接,自动生存周期;
extern int a; //a与上面的a一样(同一变量),具有外部链接,静态生存周期。注意这里的不会被默认初始为0,它只是个声明;
int b = 2; //b具有无链接,自动生存同期。并且将上面声明的b隐藏起来;
extern int c; //c与上面的c一样,维持内部链接,静态生存周期。注意这里的不会被默认初始为0,它只是个声明;
//如果去掉了extern修饰符,就跟b类似了,无链接,自动生存周期,把上面声明的c隐藏起来;
static int e; //e具有无链接,静态生存周期。并且将上面声明的e隐藏起来;初始化值为0;
static int f; //f具有无链接,静态生存周期;
}