存储类型

一、存储模型
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语句的语句标签,且函数中的所有语句标签必须唯一。
文件作用域: 任何在函数外声明的变量都具有文件作用域(全局变量)。
原型作用域: 函数原型中声明的参数名,编译器只检查参数类型,不关心参数名。
1) 局部变量(块)
函数内部定义的变量,只在本函数有效。复合语句中定义的变量在复合语句内有效;
void main() { int m, n; } char fun(int x, int y) { int i, j; } float fun(int a) { int b, c; } void main(){ int a, b; { int c; c = a+b; }
m, n 只在主函数中有效。不在整个程序中有效,函数平行。 形参也是局部变量,在整个行数中有效。 不同函数可以定义相同名字的变量,(占用的内存不同); a,b在整个main函数中有效,c在复合大括号中有效,离开复合语句就会无效。

4) 全局变量(文件)
在函数之外定义的变量为全局变量(外部变量)。全局变量可以被其他文件调用,有效范围从定义到本源文件结束,全局变量不属于某个函数,作用整个源程序。

p,q,c1,c2都是全局变量,全局变量的作用域从定义的时候开始生效。
当一个局部变量和全局变量的变量名相同时,会优先选择局部变量。
int a = 11, b = 22;
int main(void){
int a = 123
小提示:
全局变量在程序运行过程中一直占用存储单元。
一般我们会把全局变量的首字母大写(编程习惯)。
全局变量和外部变量是从不同角度提出的,全局是从作用提出的,外部是存储方式提出的,表示生存周期。

2.链接
1) 链接与作用域
多个源文件编译后,生成的目标文件以及从库函数中引用的函数会经过链接器进行链接,生成可执行文件。为了区分不同文件中的相同变量名是否为同一个变量,要用变量的链接属性(linkage)决定。
作用域是对文件内的变量的范围作标识,链接则是在不同文件间共享。
5) 链接属性(针对声明而言的):
Ø 外部(external) 多个文件中声明,表示同一个对象或函数。
Ø 内部(internal) 可在本文件声明,用static标示,在文件中使用。
Ø 空链接(none) 不同区域声明的变量属于独立的对象。
6) 链接关键字:extern、static
两个关键字用来修改变量的链接属性。
在一个默认的外部变量前面加上static后,将链接属性更改为内部链接。
int g = 5; // 文件作用域,链接属性为extern
static int do = 3; // 文件作用域,更改为internal
int main(int argc , char * argv[]) // static将变量do限定在了本文件,防止其 他项目文件引用或造成变量重名错误。
Ps:
static只对缺省链接属性为external的声明才有改变链接属性的效果。
extern 关键字可以声明一个变量,告诉要使用它的文件或函数,这个变量在别的文件内声明,这里只是引用。所以,extern扩大了一个标示符的作用域。如定义一个全局变量gm, 之后的函数可以使用gm,前面的函数就不能使用gm,加上extern 声明扩到作用域到此函数,则可以使用。

《C和指针(中文版)》上一道题,P49:
假如想着同一个源文件里写两个函数x,y,需要满足以下条件:
名字 类型 存储类型 链接类型 作域 初始值
a int static external x可以访问,y不能 1
b char static none x,y都可以访问 2
c int automatic none x的局部变量 3
d float static none x的局部变量 4
所有初始化都在声明中完成,而不是通过函数完成。
a链接属性external,应该位于所有代码块外面,但由于x可以访问,y不能,所以要出现在y函数后面,x函数前面;
b链接类型为none,则应该位于代码块内,具有代码块作用域。但是由于x,y都能访问到,所以x需要调用y,或反之。。(笔者以为,b的链接类型应该是internal,且位于文件起始处)
c,d明显要处于x的代码块内,且一个为static变量,一个automatic变量。
1. static int b = 2;
2. void y()
3. {
4. …
5. }
6. int a =1;
7. void x()
8. {
9. int c = 3;
10. static d = 4;
11. }

3.内部函数与外部函数
1) 静态函数
在函数名前加上类型关键字static就会将函数标记为内部函数,只能在本文件调用.
static int * fun(int x, int b); //static只改变了函数的作用域,并没有改变出入栈。
内部函数也叫静态函数, 一个工程多个文件时,内部函数可以很好避免不同开发人员定义函数重名的干扰。

7) 外部函数
函数首部加extern关键字就表示函数为外部函数,可以供其他文件调用。
extern int fun(int a, int b);
extern 可以省略,编译器会默认函数是外部函数。在调用文件中加extern对函数声明,则表示该函数已经在别的源文件中定义过。

小结:”存储模型.c”–《C和指针》(中文版)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值