auto、 register、 extern、 static关键字详解

1、auto
auto是C++提供的存储类声明符,用于声明自动变量。
除了auto声明符外,C++还提供了另外3个存储类声明符,分别是register(寄存器存储)、extern(外部存储)和static(静态存储)。在声明创建变量时,存储类声明符应放在数据类型声明符之前:

void demo(){
	auto int A;
}

2、register
除了auto外,还可以通过存储类声明符register来声明自动变量,与auto唯一的不同在于:关键字register通知编译器,用户希望通过CPU寄存器,而不是“栈”来处理某个变量,从而可以在一定程度上加快该变量的访问速度。用register声明的变量常称为寄存器变量。举例来说,下列代码声明了int型寄存器变量sum,并将其初始化为9,如下所示。

register int sum= 9;

需要注意的是,即使用register声明了某个变量,编译器也不一定会满足它的要求。因为,CPU寄存器可能被占用或者无法存储指定类型的数据,而且,现在的编译器一般可以自动决定应把哪些变量放在CPU寄存器中。因此,在C++程序中,register关键字很少使用。
使用register关键字会产生一定的负面效果,不管是否能满足要求,编译器认为register型自动变量是存储在CPU寄存器中的,而寄存器是没有内存地址的,所以,不能对register型自动变量进行取地址操作,下列代码是错误的
void demo(){
register int sum =0;
int * pSum =∑
}

注意 事实上,用auto和register声明的变量除了存储位置不同(一个是“栈”,而另一个可能是“栈”也可能是CPU寄存器)外,并无其他差异,我们可以将其统
称为自动变量来考虑。

3、 extern
每个C++程序对应着一块静态数据区(也称全局数据区)。在源程序编译时,编译器就为某些程序实体(某些变量及所有的常量)预分配存储地址和内存空间,程序一开始执行,这些程序实体就被创建,一直到程序结束才被撤销,并释放对应的内存空间,因此称其为“永久存储”。静态存储的程序实体的数目在程序运行过程中是不变的,因此无须使用特殊的机制(如堆、栈)来管理,编译器将分配固定的内存块来存储所有的静态存储实体。
根据用法不同,静态存储的变量可分为 “全局变量”“静态变量”
(1)extern关键字:
前面已经提到,extern是C++语言提供的存储类声明符,用extern声明的变量称为全局变量。从字面上看,这意味着该变量可以在程序的任意位置使用。全局变量是在函数和类外定义的,所以也称为外部变量。
和自动变量不同的是,全局变量的声明有两种形式:定义性声明和引用性声明
定义性声明用于创建变量,其基本形式为:

extern 类型 变量名 = 初始化表达式 ;

此时,初始化表达式不可省略,此指令通知编译器在静态数据区中开辟一块指定类型大小的内存区域,用于存储该变量。下列语句创建了一个初始值为10的double型全局变量total。

extern double total=10;

存储类extern说明符也可以省略,只要是在外部(不属于任何一个函数或类)定义的变量,编译器就将其当作全局变量。在外部定义时上述代码等价于下面的代码。

double total=10;
//注意 只有当在定义性声明中省略了extern时,初始化表达式才可省略,系统默认将其初始化为0,对于定义的全局数组或结构,编译器将其中的每个元素或
//成员的所有位都初始化为0。

在使用全局变量之前,需要对其进行引用性声明,这和函数的用法有一点类似,引用性声明只有一种格式,如下所示。

extern 类型 变量名;

请注意,这里没有初始化语句,引用性声明用于告诉编译器变量是全局的这一特征,引用性声明不只局限在外部,只要在使用全局变量之前对其进行声明即可。
定义性声明和应用性声明主要有以下3点区别:
·(1)定义性声明只能有一次,而引用性声明可以有多次。
·(2)定义性声明一定是在外部,而引用性声明的位置没有限制,只要在使用前对全局变量声明使其可见即可,关于可见性的介绍,请参考本章稍后的介绍。
·(3)定义性声明有两种形式:带extern的形式(不可缺少初始化语句)和省略extern的形式(可省略初始化语句,编译器默认初始化)。引用性声明只有带extern但不带初始化表达式一种形式。

#include <iostream>
using namespace std;
int main()
 {
        extern int num1; //   引用性声明,这句话个人感觉可以删除呢,但是不知道为啥要加上或者删除有,有啥影响,希望懂的人简要普及一下:
        cout<<"num1:"<<num1<<endl;
        void change();      // 函数声明
        change();            //函数使用
		cout<<"num1:"<<num1<<endl;
        return 0;
}
int num1;   //定义性声明

下面是func.cpp中的代码//

extern int num1;    // 引用性声明
void change()      // 函数定义
{                       
	num1+=3;
}

输出结果如下所示:
num1:0
num1:3

在这里插入图片描述
在这里插入图片描述

代码解析:

代码第12行,定义全局变量num1,放在main.cpp中。
func.cpp中函数change()对num1进行了加3处理,
在使用num1前,func.cpp的第一句便外部引用声明了全局变量 num1,这样,便可以在func.cpp内的任何位置使用num1。
num1的定义性声明省略了extern和初始化语句,编译器自动将其初始化为0。在main()函数内,访问num1之前同样要对其进行引用声明,可以看出,没有传递任何参数,change() 函数便实现了对num1的修改和访问,这也提供了一种在程序文件间进行数据通信的途径。
注意,对全局变量引用声明的时候,不能给初值。如果将 func.cpp 中的引用性声明改为:

extern int num1= 10; 

这便不再是引用性声明语句,而成了int型全局变量的定义,编译器会为其在静态数据区分配内存。实际上,main.cpp中已经定义了全局变量num1,编译器会给出变量重复定义的错误。
注意 首先,全局变量虽然方便了数据的共享,但其破坏了程序的封装型,使程序读起来比较困难。其次,全局变量占据的空间无法释放,在一定程度上浪费了内存资源。最后,滥用全局变量容易造成名字冲突和程序错误。因此,应尽量少用全局变量。

(4)static关键字

static也是C++提供的存储类声明符,使用static声明的变量称为静态变量,和全局变量一样,静态变量也是永久存储的。

静态变量与全局变量之间的区别:

)(1)·没有定义性声明和引用性声明之分,只有声明语句。静态变量应在使用前进行声明,编译器根据声明语句,在静态数据区为静态变量分配内存空间。
(2)·既可以在外部声明,也可以在内部声明。当在外部声明时(外部静态变量),所声明的标识符只限于一个文件中的函数共享;当在内部声明时(内部静态变量),所声明的标识符仅限于所在的代码块内使用,内部静态变量与自动变量的唯一区别在于内部静态变量具有永久生存期。
静态变量声明的基本形式如下所示:

static 类型 变量名= [ 初始化表达式 ];
//注意 初始化表达式可以省略,此时系统默认将其初始化为0;对于定义的全局数组或结构,编译器将其中的每个元素或成员的所有位都初始化为0。

main.cpp中的代码

#include <iostream>
using namespace std;
static int num1 = 12;
int main()
{
	cout << "num1:" << num1 << endl;
	void change();   //	声明函数
	change();        //函数使用
	cout << "num1:" << num1 << endl;
	return 0;
}

func.cpp中的代码

#include <iostream>
using namespace std;
void change()   //函数定义
{
	static int num1;  //	声明,num1仅限于该函数使用
	num1 += 3;
	cout << "num1:" << num1 << endl;

}
输出结果如下所示。
num1:12
num1:3
num1:12

【代码解析】在main.cpp第3行,声明的静态变量num1的作用范围仅限于本文件。func.cpp中的“static int num1;”相当于声明了另一个静态变量num1,其作用范围仅限于change函数内。两个静态变量都位于静态存储区,编译器通过绝对地址的不同对其加以区分。

#include <iostream>
using namespace std;

int main()
{ 
	int num1 = 5;
	void change(int);   //	声明函数
	change(num1);        //函数使用
	change(num1);        //函数使用
	change(num1);        //函数使用
	return 0;
}

func.cpp

#include <iostream>
using namespace std;
void change(int n)   //函数定义
{
	static int m = 1;//函数内部定义的静态变量m,在函数两次调用的间隔保持其值
	m += n;
	cout << "m:" << m << endl;

}
输出结果如下所示。
m:6
m:11
m:16

对内部静态变量而言,在函数两次调用之间,静态变量的值是能保持的(保存的),代码6-18是内部静态变量的使用范例。
在这里插入图片描述

在这里插入图片描述
【代码解析】在代码第14行,用static修饰的内部变量m在函数add()调用的间隔里保持着数据,换句话说,对静态变量的初始化在程序刚开始执行的时候已然完成,程序中对该变量的写入和访问都会一直存储在静态存储区中。

静态变量不像全局变量那样有定义性声明和应用性声明之分,凡是声明语句都将在静态数据区为其分配空间。
因此,应避免同一可见域的重复声明。注意 对于外部静态变量,推荐声明在文件前面(#include语句后),而对内部静态变量,推荐声明在代码块的最前面。
静态变量的名字不影响其他文件中的同名变量,它提供了隐藏程序实体的一种手段,程序员在设计不同的文件时,不必担心它会和其他文件中的标识符发生冲突。
自<< 零基础学C++>>

  • 4
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值