【C语言】存储类型说明符——auto、static、extern、register

目录

1. 变量的属性

2. 存储类型说明符

2.1 auto

2.2 static

2.3 extern

2.4 register


在声明中最多可以出现一种存储类型说明符,如果存储类型说明符存在,则必须把它放置在最前面。

1. 变量的属性

存储期

  • 自动存储期。变量在所属块被执行时获得内存单元,并在块终止时释放内存单元,从而会导致变量失去值。具有自动存储期的变量不初始化默认为随机值。
  • 静态存储期。变量在程序的执行期间一直存在。具有静态存储期的变量不初始化默认为0或空指针。

作用域

  • 块作用域。变量从定义处到所属块的末尾都是可见的。
  • 文件作用域。变量从定义处到所属文件的末尾都是可见的。

链接

  • 外部链接。变量可以被程序中的几个(或许全部)文件共享。
  • 内部链接。变量只能属于单独一个文件,但是此文件中的函数可以共享这个变量。如果具有相同名字的变量出现在另一个文件中,那么系统会把它作为不同的变量来处理。
  • 无链接。变量属于单独一个函数,而且根本不能被共享。

局部变量和全局变量有默认的属性。另外,函数也有链接属性。默认情况下,函数具有外部链接属性。

int i;     // 全局变量:静态存储期、文件作用域、外部链接

void f()   // 函数:外部链接
{
	int j; // 局部变量:自动存储期、块作用域、无链接
}

2. 存储类型说明符

2.1 auto

auto只能修饰局部变量(不包括函数形参),称为自动变量。自动变量具有自动存储期、块作用域,并且无链接。局部变量默认是自动变量,所以auto不需要明确地指出。

void f()
{
	int j; // 等价于auto int j;
}

C语言和C++auto的区别:

  • C语言中,auto是存储类型说明符,用来声明自动变量
  • C++98/03中,auto的含义与C语言相同
  • C++11中,auto仅有自动推断变量类型的功能

2.2 static

  • static修饰局部变量(不包括函数形参),称为静态局部变量。使局部变量的自动存储期属性变为静态存储期属性。
  • static修饰全局变量,称为静态全局变量。使全局变量的外部链接属性变为内部链接属性。
  • static修饰函数,称为静态函数。使函数的外部链接属性变为内部链接属性。
int i1;            // 全局变量:静态存储期、文件作用域、外部链接
static int i2; // 静态全局变量:静态存储期、文件作用域、内部链接

void f1()             // 函数:外部链接
{
	int j1;            // 局部变量:自动存储期、块作用域、无链接
	static int j2; // 静态局部变量:静态存储期、块作用域、无链接
}

static void f2()   // 静态函数:内部链接
{}

2.3 extern

全局变量具有文件作用域,即从定义处到所属文件的末尾都是可见的。如果在定义点之前想使用全局变量,用extern对该变量作“外部变量声明”,表示该变量是一个已经定义的外部变量。

#include 

int main()
{
	extern int gValue1;
	extern int gValue2;
	int sum = gValue1 + gValue2;
	printf("sum = %d\n", sum);
	return 0;
}

int gValue1 = 25;
int gValue2 = 10;

“外部变量声明”也能使全局变量能够跨文件被访问。

// 源文件a.cpp中定义了全局变量a
int a = 10;
// 源文件b.c声明a
extern int a;
// 之后就可以使用a了

extern也能修饰函数,但是就和auto修饰变量一样,没什么用。

变量声明和定义的关系:

声明(declaration)使得名字为程序所知,一个文件如果想使用别处定义的名字则必须包含对那个名字的声明。而定义(definition)负责创建与名字关联的实体。

变量声明规定了变量的类型和名字,在这一点上定义与之相同。但是除此之外,定义还申请存储空间,也可能会为变量赋一个初始值。

如果想声明一个变量而非定义它,就在变量名前添加关键字extern,而且不要显式地初始化变量:

extern int i; // 声明i而非定义i
int j;        // 声明并定义j

任何包含了显式初始化的声明即成为定义。我们能给由extern关键字标记的变量赋一个初始值,但是这么做也就抵消了extern的作用。extern语句如果包含初始值就不再是声明,而变成定义了:

extern double pi = 3.1416; // 定义

在函数体内部,如果试图初始化一个由extern关键字标记的变量,将引发错误。

变量能且只能被定义一次,但是可以被多次声明。

2.4 register

register只能修饰局部变量(包括函数形参),称为寄存器变量。register是唯一能修饰函数形参的存储类型说明符。

声明变量具有register存储类型就要求编译器把变量存储在寄存器中,而不是像其他变量一样保留在内存中。寄存器是驻留在计算机CPU中的存储单元。存储在寄存器中的数据会比存储在普通内存中的数据访问和更新的速度更快。指明变量的存储类型是register是一种请求,而不是命令。编译器可以选择把register型变量存储在内存中。

和自动变量一样,寄存器变量具有自动存储期、块作用域,并且无链接。不同的是,由于寄存器没有地址,所以对寄存器变量使用取地址运算符&是非法的。即使编译器选择把变量存储在内存中,这一限制仍适用。

void f(register int i) // register也能修饰函数形参
{
	register int j; // 寄存器变量:自动存储期、块作用域、无链接
}

你可能感兴趣的:(C语言,c语言)