C 变量的存储类型

积木网络|C语言中的变量具有两种属性:一个是数据类型,一个是存储类型。根据变量所存放的数据的性质不同而分为各种数据类型;根据变量的存储方式不同而分为各种存储类型。变量的数据类型决定了该变量所占内存单元的大小及形式;变量的存储类型规定了该变量所在内存中的存储区域,因而规定了该变量作用时间的长短,这种性质又称为“存在性”。变量在程序中声明的位置决定了该变量的作用域,即在什么范围内可以引用该变量,“可引用”又称为“可见”,所以这种性质又称为“可见性”。

计算机的内存和CPU中的寄存器都可以存放数据,变量究竟存放在何处则由存储类型来决定。变量的存储类型用来说明变量的作用域、生存期、可见性和存储方式。

1)什么是作用域?
作用域是该变量在其中有定义的程序部分,通俗的说,是该变量起作用的程序中的某个区域。

2)什么是变量的生存期?
变量的生存期是指它从产生到消亡的存在时间,即变量从定义开始到所占有的存储空间被系统收回为止的这段时间。

3)什么是变量的可见性?
在某个程序区域,若可以对某个变量进行访问操作,则称为该变量在该区域为可见的,否则为不可见的。

4)什么是全局变量和局部变量?
在一个函数内部或复合语句内部定义的变量称为内部变量,又称为“局部变量”。在函数外定义的变量称为外部变量,又称为全局变量。

5)什么是动态存储变量和静态存储变量?
在程序运行期间,所有的变量均需占用内存,有的是临时占用内存,有的是程序运行过程中从头到尾占用内存。在程序运行期间,根据需要进行临时性动态分配存储空间的变量称为动态存储变量,永久性占用内存的变量称为静态存储变量。

对于一个正在运行的程序,可将其使用内存从上到下分为三个区域:
1)程序代码区:程序的指令代码存放在程序代码区。
2)静态存储区:静态存储变量存放区包括全局变量。
3)动态存储区:存放局部自动变量、函数的形参以及函数调用时的现场保护和返回地址等。

变量的定义的一般形式为
<存储类型><数据类型>变量名表;

存储类型包括:
auto, 自动型
register,寄存器型
extern,外部参照型
static,静态型

自动变量用auto声明,在函数内或复合语句中定义自动变量时auto可以缺省。自动变量只在定义它的函数或复合语句内有效。当在程序开头声明时,它做为一个全局变量,但对函数内部再次声明同名的变量的值不影响。

寄存器型变量register在函数内或复合语句内定义,所以它也是局部变量,存储在CPU的通用寄存器中,因为数据在寄存器中操作比在内存中快,因此通常把程序中使用频率最高的少数几个变量定义为register型。但并不是用户定义的寄存器型变量都被放入CPU寄存器中,能否真正把它们放入CPU寄存器中是由编译系统根据具体情况做具体处理的。

分配寄存器的条件是:
1)有空闲的寄存器;
2)变量所表示的数据的长度不超过寄存器的位长。

外部参照型变量extern(全局变量)
extern型变量一般用于在程序的多个编译单位之间传送数据,在这种情况下指定为extern型的变量是在其它编译单位的源程序中定义的,它的存储空间在静态数据区,在程序执行过程中长期占用空间。若要访问另一个文件中定义的跨文件作用域的全局变量,则发必须进行extern说明。如果在程序的开头部分定义了extern变量,则是告诉编译器,这个变量是外部参照变量,应该在本程序之外去寻找它的定义。也就是说,通过extern可以把全局变量扩展到另一个程序文件中。如果全局变量不在程序的开头部分定义,则这个全局变量的作用范围只限于从定义处到程序的结束。

静态型变量static

静态型变量既可以在函数或复合语句内声明,也可以所有函数之外声明。在函数或复合语句内部定义的静态变量称为局部静态变量,在函数外部定义的静态变量称为全局静态变量。有时希望函数中的局部变量的值在函数调用结束后不消失而保留原值,即其占用的存储单元不释放,在下次调用该函数时,该变量已有值,其值就是上一次函数调用结束时的值,这时应该指定该局部变量为静态局部变量,用关键字static进行声明。

静态型变量的生存期是全局的,其意思就是一但定义了静态变量,那么只有到整个程序结束,这个变量的生存期才结束,它的内存才被释放。唯一不同的是它的作用域分局部和全局。

注意事项:
1)静态局部变量属于静态存储类型,在静态存储区内分配存储单元。在程序整个运行期间都不释放。而自动变量(动态局部变量)属于动态存储类型,占动态存储空间而不占静态存储空间,函数调用结束后即释放。
2)对静态局部变量只赋初值一次,以后每次调用函数时不再重新赋初值而只是保留上次函数调用结束时的值。而对自动变量赋初值,每调用一次函数就重新给一次初值,相当于执行一赋值语句。
3)在定义局部变量时不赋初值,则对静态局部变量来说,编译时自动赋值初值0(对数值型变量)或空字符(对字符变量)。而对自动变量来说,如果不赋初值,则它的值是一个不确定的值。这是由于每次函数调用结束后存储单元已释放,下次调用时又重新另配置存储单元,而所分配的单元中值是不确定的。
4)有时在程序设计中希望某些外部变量只限于被本文件引用,而不能被其他文件引用,这时可以在定义外部变量时加一个static声明。


小结:
1)类型说明。关键字auto,static,register用于定义变量的存储类型说明,其中auto通常缺省。而关键字extern则不然,它不是用于定义变量,而是用于说明某个变量,是已在本函数之外或其他源文件中定义过的外部变量。extern说明有“延伸外部参照型变量作用域”的作用。
2)变量的作用域和生存用周期
auto,register,局部static型 是局部变量,auto,register,具有局部生存周期,而局部static变量具有的全局生存周期;全局static型,外部参照型是全局变量,具有全局生存周期。
由上面两点可以看出,只要是static型变量,不管它是全局的还是局部的,其生存期都是全局生存期,所占用的内存空间只有到程序结束才释放。
3)变量的初始化

对外部参照变量的初始化不能在进行extern说明时进行。对于全局变量和静态变量来说编译时自动赋值初值0(对数值型变量)或空字符(对字符变量)。



### C语言中的变量存储类别 #### 动态存储方式 当定义一个具有`auto`存储类别的变量时,默认情况下,所有局部变量都属于此类别。这些变量仅在其被声明的作用域内有效,并且每次进入该作用域都会重新创建它们;离开此范围后就会自动销毁。这意味着如果函数再次调用,则会分配新的内存空间给这个变量。 ```c void func() { auto int a; // 'a' 是动态分配的局部变量 } ``` 这种类型的变量通常用于临时性的计算或者作为函数内部操作的一部分[^2]。 #### 静态存储方式 通过使用关键字 `static` 来修饰局部变量可以使其成为静态局部变量。这类变量在整个程序执行期间只初始化一次,并且即使在它所属的功能结束之后仍然保持其值不变直到下一次访问为止。这使得它可以用来保存状态信息而不需要每次都传递参数或返回多个结果。 ```c int counter() { static int count = 0; return ++count; } ``` 此外,还可以应用于全局范围内使某些数据成员仅限于文件级别可见度而不是整个项目中共享。 #### 寄存器存储方式 利用 `register` 关键字建议编译器尝试将特定变量放置到 CPU 的寄存器里而非 RAM 中以提高性能效率。然而实际上能否成功取决于硬件资源以及优化设置等因素的影响。因此这是一种提示性质的做法并不总是能得到预期的效果而且现代编译工具往往能够自行决定最佳方案所以较少见到了。 ```c void increment(register unsigned long *ptr) { (*ptr)++; } ``` 需要注意的是随着计算机架构的发展变化, 这种做法已经变得不那么重要了因为现在的处理器拥有更复杂的缓存机制来处理频繁使用的数据。 ### 不同存储类别的区别与应用场景 - **生命周期**: 自动(`auto`) 和寄存器 (`register`) 类型的变量存在于栈上并随函数调用周期存在和消失;相反地,静态 (`static`) 变量则持续存在于堆外区域直至应用程序终止。 - **初始赋值行为**: 对于自动和寄存器变量而言,除非显式赋予初值否则默认为未定义的状态;而对于静态变量来说一旦声明即会被零化(数值类型)或是空指针(NULL) (指向对象/函数). - **作用域限制**: 局部静态变量可以在同一源文件内的其他地方继续保留上次退出后的最新状态而不影响外部世界. 综上所述,在选择合适的存储类别之前应该充分考虑上述因素以便更好地控制程序的行为模式从而达到更高的可读性和维护性水平.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值