C语言存储类:
我们从三个不同角度来描述储存类:
1.作用域 2.链接类型 3.存储期
声明对象时使用的存储类说明符以及声明的上下文共同决定了对象的存储类。
自动存储类/静态存储类/寄存器/外部存储类/关键字(typedef)
一. 作用域:
1. 代码块作用域
2. 函数原型作用域
3. 文件作用域
4.
二.链接类型
C语言的链接有三种,外部链接,内部链接,空链接
1. 外部链接:公开数据和公开方法,其他文件也可调用。(例如,普通函数和全局变量),关键字extern是用来声明的,当一个文件调用到其他文件的变量或者函数时,要在文件中用extern 来申明。
2. 内部链接:只在本文件内部可以调用,外部文件无法访问。(例如,Static修饰的函数和Static 修饰的全局变量)用static修饰函数可以避免被其他程序错误的调用,例如当两个文件中都有一个叫function的函数时,主函数在调用时就不明确要调用哪一个,把其中一个function函数声明为static可以解决这个问题。
3. 空链接:(局部变量,static修饰的局部变量)
三 存储期:
1.自动存储期对象对于一个程序块来说是局部的,在退出程序块时该对象将消失。
(自动存储类自动进行内存的分配和释放。)
(1) 如果没有使用存储类说明符,或者如果使用了auto限定符,则程序块中的声明生成的都是自动存储类对象。(例如局部变量,函数的形参…..
(2) 自动存储类在程序被调用时,往往存储在内存中的栈空间中。
(3) 声明为register的对象也是自动存储类,并且如果可能,将被存储在机器的快速寄存器中。
2.静态储存期:特点在退出和进入函数或程序块时其值将保持不变。
(1) 在一个程序块内,静态对象用关键字static声明。(Static 局部变量)
static修饰的局部变量具有继承性,下一次访问保存上一次访问的状态和值。
(2) 在所有程序块外部声明且与函数定义在同一级的对象总是静态的。(全局变量)
(3)Static修饰的全局变量也是静态的(全局变量本身就是静态的),只不过这个全局变量是有内部链接的。(Static 全局变量)
(4)申明的外部变量(extern)也具有静态存储期,也只有在编译的时候赋值一次。
(5)定义为静态储存类的变量在程序被调用时,是分布在数据段中的。
C语言的动态存储分配:
1.动态存储分配都在堆区中进行。
2.调用malloc可以动态的分配内存,调用free可以释放内存。所以使用相对灵活。
3.动态存储类没有名字,分配使要用讲malloc函数返回的内存空间首地址赋给一个指针。
4.分配好的内存在程序调用过程中一直存在,直到用free释放它,或者进程结束。
存储类说明符有auto, register, static, extern和typedef。
(1) auto和register将声明的对象说明为自动存储类对象,这些对象仅可用在函数中。这种声明也具有定义的作用,并将预留存储空间。register说明的声明等价于auto说明的声明,所不同的是,register暗示了声明的对象将被频繁地访问,将尽可能存储在寄存器中。如果一个对象被声明为register,则将不能对它应用一元运算符&,声明为register但实际按照auto类型处理的对象的地址进行计算是非法的。
(2) static将声明的对象说明为静态存储类。这种对象可以用在函数内部或者函数外部。在函数内部,该说明符将引起存储空间的分配,具有定义的作用。退出函数时改存储空间不被释放。在函数外部,该说明符将引起声明对象为具有内部链接。
(3) 函数内部的extern声明表明,被声明的对象的存储空间定义在其他地方。在函数外部,说明声明的对象具有外部链接。
(4) typedef说明符并不会为对象预留存留空间。之所以将它称为存储类说明符,是为了语法描述上的方便。
类型限定符可以用于指定被声明对象的特殊属性,可以与任何类型说明符一起使用。类型限定符有:const和volatile。
(1) const用于声明可以存储在只读存储器中的对象,并可能提高优化的可能性。可以对const对象进行初始化,但在初始化以后不能进行赋值。
(2) volatile用于强制某个实现屏蔽可能的优化(详细说明请见《voliate》文章)
总结一下以上关键字说明的对象:
(1) static-静态变量,作用范围在一个文件内,只有在文件内的代码可以访问;
(2) register-寄存器变量,可能的情况下会直接存放在机器的寄存器中;
(3) auto-存储类型标识符,表明变量具有本地范围、块范围的声明;
(4) extern-外部链接,即该变量或函数在其他文件中可见;
(5) const-对象或变量不能被改变,能提高程序的健壮性;
(6) volatile-volatile应该解释为“直接存取原始内存地址”避免优化
结论:
1. 如果在不同的文件中定义相同名字的变量,编译器无法通过编译。
2. 使用extern可以访问其他文件中定义的变量。
3. 使用static标示的变量在文件内部有效,其他文件中无法访问。
4. 使用static标示的函数,在其他文件中不能访问。