auto、register、static、extern等存储类修饰符的区别

开发 后端
存储类型修饰符可以修改标识符的链接和对应对象的生存周期;标识符有链接,而非生命周期;对象有生存周期,而非链接;函数标识符只可用static、extern修饰,函数参数只可用register修饰。

存储类型修饰符可以修改标识符的链接和对应对象的生存周期;标识符有链接,而非生命周期;对象有生存周期,而非链接;函数标识符只可用static、extern修饰,函数参数只可用register修饰。

一、标识符的链接(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时,注意不能重复定义,否则编译报错,如:

程序文件一:

  1. extern int a = 10; //编译警告,extern的变量最好不要初始化 

 

程序文件二:

  1. extern int a = 20; //重复定义,应改为extern int a; 

 

一般最好这样,如果需要初始化,可把extern修饰符去掉(但也不要重复定义),另外如果其它程序文件也需要用到该变量,可用extern来声明该变量。这样会比较清晰。

(5)缺省修饰符

函数内,与auto相同;函数外,与extern相同。


 

例子:
 

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

【编辑推荐】

  1. 浅谈C/C++中的顺序点和副作用
  2. C++连接mysql数据库的两种方法
  3. C++中的指针用法汇集
  4. C++ Virtual详解
责任编辑:于铁 来源: 雨中的蓑衣
相关推荐

2009-08-27 11:04:08

C# extern修饰

2009-09-02 17:04:35

C# Extern修饰

2009-08-24 16:49:39

C#修饰符

2009-06-12 14:46:05

static修饰符Java教程

2011-07-20 16:48:22

C++static

2011-06-02 14:51:07

JAVA修饰符

2009-08-21 13:58:06

C# virtual修

2009-08-27 11:12:03

C# abstract

2009-08-27 13:06:13

C# new修饰符

2009-09-02 17:14:28

C#修饰符

2023-12-29 09:01:27

SwiftUI视图修饰符

2009-08-27 11:16:40

C# sealed修饰

2009-09-04 11:06:40

C#访问修饰符

2009-07-22 08:45:35

Scala超类构造器override修饰符

2015-08-18 09:25:11

Java修饰符关键词

2010-01-11 18:46:15

VB.NET修饰符

2011-06-28 09:29:11

C#修饰符

2009-06-12 13:37:47

访问权限修饰符Java教程

2021-08-02 12:33:26

Swift修饰符视图

2011-07-20 16:50:39

inlinec++
点赞
收藏

51CTO技术栈公众号