一、
存储模型
1.
存储类型
(storage class)
变量可以通过
生存周期(
内存占用时间->
静态与动态)
。
作用域(
有效区域->
全局与静态)
、连接点来描述。
1)
auto
普通
局部变量,
是自动存储,
变量会自动分配和释放,
函数内的变量
和
复合语句
内声明的变量,在系统运行时分配空间赋初值,在调用结束时释放空间,
这类变量就是auto
变量,
auto
变量由系统自动分配在
栈空间。auto
可以省略。
auto
变量在代码块内。
栈空间值不初始化数值不确定。
全局变量不能声明为auto
类型,因为两者在内存分配上机制不同。
1)
static
静态数据类型,定义的数据存放在全局数据区,编译的时赋初值,程序结束才释放空间。没有初始化的
static
变量值为
0
。
函数形参不能声明为静态类型,
函数形参通过堆栈完成,用于支持递归调用。
函数外定义的变量会具有内部链接属性,作用域从定义开始到文件结束
非本文件不能引用。
函数内定义的static
变量是空链接属性,作用域在本函数。
静态函数是在函数前加
static
,汇编时只是把
.globle
符号去掉,使函数只在本文件生效,参数依然进出栈。
static
其实这个关键字有三个作用,而不仅仅是存储类型。请看下面代码:
// 1.
修饰函数,使其只能在本文件可见
static void func(void)
{
static int n = 0; // 2.
修饰局部变量,使其存储在静态区(存储类型)
printf("%d\n", n);
}
static int global; // 3.
修饰全局变量,使其只能在本文件可见
注意到,static
在C
语言中的三个作用,其中第1
和第3
个作用其实都是一样的,改变的是函数或者变量的可见范围。
只有当用static
来修饰局部变量的时候,它的作用才是代表一个存储区域。
2)
register
请求编译器将变量保存在寄存器中,
从而加快程序的运行,
对于频繁使用的变量,存放在寄存器中可以减少和内存读取
(
程序中遇到变量时用控制器发指令将变量的值送到运算器中,需要存数再保存到内存中
)
。
register
只能对局部变量和
函数形参声明
(
全局变量不可申请register
类型)
。???
register
不能取址,
register int j; int *p=&j;
是不允许的,
因为无法对寄存器定制。
register
申请存放在寄存器时,不一定成功,
因为寄存器数量有限,
在申请失败时,会默认成auto
类型。
cpu
的寄存器对数据类型有限制,
不是所有类型变量都可以申请为寄存器类型。如:有些系统只支持将int
、char
和指针变量定义为register
。
3)
extern
extern
把变量说明为外部变量,表示这些变量已在其它文件中定义,编译系统不再为它们分配内存空间。
1.
作用域
(scope)
作用域是变量在程序中被使用的区域。编译确认不同的类型的作用域有4
种:
文件作用域、函数、代码块(block scope)
、原型作用域(prototype scope)
。
代码块作用域:
是在大括号{ }
内定义的部分;
函数作用域:
只适用于goto
语句的语句标签,
且函数中的所有语句标签必须唯一。
文件作用域:
任何在函数外声明的变量都具有文件作用域(