本章内容总结了作用域,分别对作用域、链接、存储期、存储类型进行概况。
C语言 | 快速了解C的发展史李
C语言 | 【耗费一夜总结三本C语言系列】之 指针、数组 一文透彻~~~李
C语言 | 【耗费一夜总结三本C语言系列】之 结构体、联合、枚举李
C语言 | 【耗费一夜总结三本C语言系列】之 声明李
C语言 | 【耗费一夜总结三本C语言系列】之 作用域 在也不用担心分不清变量的作用域拉!!!李
C语言 | 【耗费一夜总结三本C语言系列】之 编译步骤 会用C还不知道C如何编译???李
C语言 | 【耗费一夜总结三本C语言系列】之 数据类型总结李
C语言 | 【耗费一夜总结三本C语言系列】之 位及进制的用法李
文章目录
- 前言
- 一、数据存储路♂️
- 二、存储类别♂️
- 2.1 作用域
- 2.1.1 块作用域
- 2.1.2 函数作用域
- 2.1.3 函数原型作用域
- 2.1.4 文件作用域(全局变量)
- 2.2 链接利♂️
- 2.2.1 外部链接【全局作用域】
- 2.2.2 内部链接【文件作用域】
- 2.2.3 无链接
- 2.3 存储期慄♂️
- 2.3.1 静态存储期
- 2.3.2 线程存储期
- 2.3.3 自动存储期
- 2.4 变量栗♂️
- 2.5 存储类型♂️
- 2.5.1 自动变量
- 2.5.2 寄存器变量
- 2.5.3 块作用域【局部】的静态变量
- 2.5.4 外部链接的静态变量
- 2.5.5 内部链接的静态变量
- 2.6 归纳表暈
二、存储类别♂️ 2.1 作用域众所周知,数据存储在内存中。C的强大之处能够让程序员通过内存管理系统中指定变量的作用域和生命周期。从硬件角度来看,每个值都需要占用一定的物理内存。
- 而在C中一块内存则被称为对象。该对象可被存储一个、多个、甚至没有存储值;
- 标识符(a)可用来访问对象的内容int a = 10;
- 存储期描述了对象在内存的保存的时间;
- 作用域和链接描述标识符,具有多种情况:
作用域:
- 多文件共享;
- 特定文件;
- 特定函数;
- 函数的某部分;
用于描述程序中标识符可被访问的区域;可以说标识符声明的位置决定了它的作用域。
几种作用域:
2.1.1 块作用域
- 块作用域;
- 函数作用域;
- 函数原型作用域;
- 文件作用域;
范围:在代码块声明的起始位置到块结尾;
- 局部变量都具有块作用域;
什么是块:位于一对花括号之间,或者函数中任意的复合语句;
拓展
在C99以前,块作用域的变量都必须声明在块的开头。而C99允许了在块中任意位置声明变量;
// C99前使用for循环 int i; for(i=0; i<10; ++i) ... // C99修订后 for(int i=0; i<10; ++i) ...
该特性不仅仅在for循环,也应用到了while等各种语句。
举个栗子:
以下标记中的变量都为块作用域;
注意
2.1.2 函数作用域应尽量避免在嵌套代码块中出现相同的变量名。为什么编译器可以把不同代码块的变量存储域同一个内存地址呢?若不是嵌套的代码块有且仅有一个代码块处于活动状态,它们的作用域无重叠状态,且变量不能同时存在,也不会同时存在。
2.1.3 函数原型作用域范围:一个标签出现,直至函数结束,且为了防止混淆,标签尽量是唯一的;
- 只适用于goto语句标签;
2.1.4 文件作用域(全局变量)范围:从形参定义到原型声明结束;
- 只适用于函数原型中的形参名,使用时无需与声明中的形参名匹配;
- 类型重要,形参名可省略,但变长数组的形参名需要;
2.2 链接利♂️范围:从定义开始到文件末尾;
- 定义在代码块之外的变量,且函数名也有具有文件作用域;
标识符的作用域与链接属性相关;
几种链接属性
2.2.1 外部链接【全局作用域】
- 外部链接【extern】;
- 内部链接;
- 无链接
可在多个源文件内使用,标识符不论在几个源文件内被声明多少次都属于一个实体;
- 一般使用extern用于外部链接,在使用其他源文件时,需声明,便于解读;
- 当extern的标识符,可使用static来改变它的链接属性;
案例
test.h
int x = 10;
main.cpp
#include#include #include #include "test.h" extern int x; void test01(){ int x = 1; std::cout << "不加extern " << x << std::endl; } void test02(){ std::cout << "直接使用 "<< x << std::endl; } void test03(){ extern int x; std::cout << "函数内在使用extern " << x << std::endl; } int main(int argc, char *argv[]){ test01(); test02(); test03(); return 0; }
2.2.2 内部链接【文件作用域】运行结果:
该链接属性的变量只能在一个翻译单元内使用;在同一个源文件内所有声明都指向一个实体,位于不同源文件则分属于不同实体。
- 一般使用static用于内部链接;
- extern无法改变static的链接属性;
翻译单元
2.2.3 无链接即一个源文件和它所包含的头文件;
2.3 存储期慄♂️具有块作用域、函数作用域、函数原型作用域的变量都属于无链接变量;
描述了标识符访问的对象的生存期;
几种存储期
2.3.1 静态存储期
- 静态存储期;
- 线程存储期;
- 自动存储期;
- 动态分配存储期;
2.3.2 线程存储期存在周期:程序执行期间直至程序结束;
- 文件作用域具有静态存储器;
- 此处的静态与static不为同一类别;
- 静态存储期包括了内部链接、外部链接所有的文件作用域变量;
- 块作用域也可以有静态存储期;
2.3.3 自动存储期存在周期:从被声明到线程结束;
- 可使用_Thread_local即可获得变量的私有备份;
2.4 变量栗♂️存在周期:当一个变量在块内声明,到块结束时,该变量会自动释放内存。
- 当该变量释放后,其内存地址可继续被使用;
- 块作用域(局部变量)一般都有自动存储期;
- 变长数组较为特殊,存储期是从声明到块的末尾;
几种变量
2.5 存储类型♂️ 2.5.1 自动变量
- 自动变量;
- 寄存器变量;
- 块作用域的静态变量;
- 外部链接的静态变量;
- 内部链接的静态变量;
2.5.2 寄存器变量
- 即块作用域【自动存储期、无链接】中的变量;
- 内层块会隐藏外层块的定义;
2.5.3 块作用域【局部】的静态变量通常变量都保存在内存当中,而寄存器变量则存储在CPU的寄存器中,更加高效。
- 寄存器的地址无法获取;
- 其变量与自动变量几乎一致;
- 具有静态存储期;
- 可声明为register的数据类型有限,例如double由于没有足够大的空间;
- 使用只需在声明的时候加上register关键字;
此处的静态应理解为该变量再内存中的地址不改变,值可变;
- static变量不能使用在形参中;
- 为内部静态存储类别;
函数块内使用static
#include#include #include int test01(){ static int a = 10; return a; } int main(int argc, char *argv[]){ int x = test01(); std::cout<< x << std::endl; return 0; }
2.5.4 外部链接的静态变量由于变量在函数结束后即释放,所以无法将变量返回【有些编译器有优化,能够成功返回。如果将该变量多打印几次即会出错】。为了解决该问题,即可在变量声明前加上static关键字,保证了函数结束后,该变量不会被释放。
2.5.5 内部链接的静态变量外部变量,可在其他文件中进行访问;
- 外部变量具有静态存储期,即直至函数结束;
- 具有文件作用域、外部链接、静态存储期;
- 为外部存储类别;
- 在其他文件使用时,必须使用extern进行声明;
- 若外部变量没有被初始化,则会被初始化为0;
只属于一个文件内部使用,定义在文件开头,直至文件结束;
- 具有静态存储期,文件作用域和内部链接;
- 可使用extern在函数内部对其声明,但不会修改它的链接属性;
小结
- 程序运行时变量存储的位置在以下三个:
- 普通内存;
- 运行时堆栈;
- 硬件寄存器;
- 不属于堆栈的变量 - 静态变量;
- 静态变量与外部变量未初始化则会被自动初始化为0;
- 存储类别说明符:auto、register、static、_Thread_local、typedef;
test.h
int x;
main.cpp
#include#include "test.h" static int a; extern int x; int main(int argc, char *argv[]){ std::cout << "静态变量: " << a << std::endl; std::cout << "外部变量: " << x << std::endl; return 0; }
结果
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)