生存期
可以从时间角度作为切入点,分析变量的生存期。
C语言的变量拥有两种生存期,分别是静态存储(static storage duration)和自动存储期(automatic storation)。
具有文件作用域的变量具有静态存储期(如全局变量),函数名也拥有静态存储期。具有静态存储期的变量在程序执行期间将一直占据存储空间,直到程序关闭才释放。
具有代码块作用域的变量一般情况下具有自动存储期(如局部变量和形式参数),具有自动存储期的变量在代码块结束时将自动释放存储空间。

上面代码中全局变量A,B.C,不论是内部链接属性还是外部链接属性,它们都拥有文件作用域,func和main两个函数也拥有文件作用域,因此它们的生存期具有静态存储期,只有当程序关闭的时候,它们所占的内存空间才会被释放。而定义于func函数内的局部变量a,b,c和形参m,n,以及定义于main函数内部的局部变量i,j,k,,它们都拥有代码块作用域,因此它们的生存期具有自动存储期,变量所占的内存空间 在代码块结束时将自动被释放。
存储类型
C语言变量的作用域,链接属性和生存期,这些都是由变量的存储类型来定义的。变量的存储类型其实是指存储变量值的内存类型,C语言提供了五种不同的存储类型,分别是auto,register,exten和typedef。
自动变量
在代码块中声明的变量默认的存储类型就是自动变量(auto),使用关键字auto来描述。所以,函数中的形参,局部变量以及复合语句中定义的局部变量都具有自动变量。自动变量拥有代码块作用域,自动存储期和空链接属性。

由于这是默认的存储类型,所以不写auto是完全没有问题的。但有时候,如果想强调局部变量屏蔽同名全局变量这一做法,可以在该局部变量的声明处加上auto,这样做可以使得代码更清晰:

寄存器变量
寄存器是存在于CPU内部的,CPU对寄存器的读取和储存可以说几乎没有任何延迟时。
将一个变量声明为寄存器变量(register),那么该变量就有可能被存放于CPU的寄存器中。因为寄存器空间十分有限,所以编译器并不会让你将所有声明为register的变量都放到寄存器中。事实上有可能所有的register关键字都被忽略,因为编译器有自己的一套优化方法会权衡哪些才是最常用的变量。而那些被忽略的register变量,它们会变成普通的自动变量。
寄存器变量和自动变量在很多方面一样,它们都拥有代码块作用域,自动存储期和空连接属性。
不过这里有一点需要注意:若将变量声明寄存器变量那么就没办法通过取址运算符(&)获得该变量的地址。


静态局部变量
static用于描述具有文件作用域的变量或函数时,表示将其连接属性从external修改为internal,那么效果又不一样
默认情况下,局部变量是auto类型,具有自动存储期的变量。如果使用static来声明局部变量(static)。static使得局部变量具有静态存储期所以它的生存期与全局变量一样,存储空间直到程序结束从释放。


count本来是一个普通的局部变量,但当我们在前面使用static描述后,它就大变样了。因此它能够“记住”上一次保存的值。因为这里count是静态局部变量,所以它只初始化一次,再执行func函数,并不会重复初始化count。另外虽然静态局部变量具有静态存储期。但它的作用域仍然是局部变量,所以在别的函数中是无法直接使用变量名对其进行访问的。
4.static和extern
static和extern的作用域是文件作用域,static关键字使得默认具有external链接属性的标识符变成internal的链接属性,而extern关键字则是告诉编译器这个变量或函数在别的地方已经定义过了。
看下面例子就会发现就算不写extern,编译器也不会出现任何提醒或报错,程序也可以正常执行;



其实这个extern与auto类似,在大部分情况下,它的作用是使程序更健全,代码更清晰易懂,所以还建议是要加上的。比如,在func.c源文件中声明的count,如果不写上extern,会让人以为这里要定义一个全新的全局变量,而事实上,这里只是对count进行声明,它里面存放的值是test27.c源文件中初始化的520


总的来说,使用auto或register关键字声明的变量具有自动存储期,而使用static或extern关键字声明的变量具有静态存储期。
typedef与其他四个存储类型语句不同,typedef与内存存储无关,用于为数组类型定义的一个新名字。