变量的存储持续性,作用域和链接性

存储持续性
存储持续性分为自动存储持续性,静态存储持续性,动态存储持续性。
自动存储持续性:在函数中或者代码块中定义的变量的存储持续性是自动的。执行函数或代码块时,变量被创建,执行完之后,该变量使用的内存被释放。
静态存储持续性:在函数外定义的或者用static关键字定义的变量的存储持续性是静态的。它在整个程序运行过程中都存在。
动态存储持续性:用new分配的内存,直到用delete才会被释放。
作用域和链接性
作用域是指变量的可见范围。比如函数内定义的变量的作用域是从定义的地方开始到函数结束位置。
链接性是指变量在不同文件中的共享程度。外部链接性代表变量可以被多个文件共享,内部链接性表示变量只能有它所属的文件中使用。
自动存储持续性
在默认情况下,在函数中声明的参数和变量的存储持续性是自动的,作用域为局部,没有链接性。需要注意的是,执行到代码块时,将为变量分配内存,但其作用域的起点是其声明的位置。
下面介绍C++编译器是如何处理自动变量的:
常用的方法是留出一段内存,把它看成栈。当函数被调用时,自动变量被压入栈中,栈顶指针指向变量后面下一个可用的内存单元。函数结束后,栈顶指针重新指向以前的位置,之前的变量没有被删除,但不再被标记。它所占据的空间的值将被下一个入栈的变量覆盖。
静态持续变量
静态持续性变量的链接性有3种:外部链接性(多个文件共享),内部链接性(所属文件可用),无链接性(所属函数或代码块可用)。
int a = 3;  //静态变量,外部链接性
static int b = 4;  //静态变量,内部链接性

void fun()
{
	static int c = 5;  //静态变量,无链接性
}
外部链接性的静态变量
外部链接性的静态变量可以在一个项目的多个文件里共享。需要关键字extern。
如在file1.cpp中定义了外部链接性的静态变量a,则在file2.cpp中要用带extern的声明语句,才能使用在file1.cpp中的a。
extern int a;

并且在file2.cpp中不能有这种语句
int a;

编译不会出错,运行会发生错误。这相当于定义了两个a,而且这两个a的作用域是一样的,因此编译器不会区分。在作用域不同的时候才可以定义同名变量:
int a = 2;

void fun()
{
	int a = 3;  //这是自动变量,会覆盖掉全局静态变量a
}
内部链接性的静态变量
内部链接性的静态变量的作用域是所属的文件中,因此就算在别的文件中定义了同名的外部链接性的静态变量,也不会发生冲突。
file1.cpp
static int a;  //内部链接性的静态变量

file2.cpp
int a;  //外部链接性的静态变量

在file1中,对file2的a是不可见的,因为会被覆盖掉。
还需要注意的是const对链接性的影响:
const int a = 1;  //尽管没有static关键字,但const关键字也代表该静态变量是内部链接性的
extern const int b = 1; //b是外部链接性的,使用了extern覆盖掉了const默认的内部链接性
上面的第二条语句说明常量b是外部链接性,又因为是常量,所以必须在一个且只有一个文件中初始化该常量。
无链接性的静态变量
在函数或代码块内定义并被关键字修饰的是无链接性的静态变量。它只有在执行到所属的代码块时才可用,但是离开代码块之后,它的内存单元没有被释放,始终存在,直到程序结束。而且初始化的只在第一次执行,下次在进入相应的代码块时,将不再执行初始化动作。这和自动变量有很大的区别。
	int *p;
	{
		static int a = 1;  
		p = &a;
		cout << a << endl;
	}

	cout << a << endl;  //这里编译会错误,因为a未被定义
	cout << *p << endl;  //但静态变量a的内存没有被释放,始终存在
	                     //所以可以通过地址来访问
动态分配内存
编译器使用三块独立的内存,一块用于静态变量,一块用于自动变量,还有一块用于动态存储。
使用new分配的内存都属于动态存储。现在主要介绍定位new运算符。
通常的new是随机分配的内存,但通过定位new运算符,程序员可以自己指定被分配的内存的地址。不能delete由定位new运算符分配的内存。
	int a[4] = { 1,2,3,4 };
	int *p = new(a) int[4];  //被分配给p的地址是数组a的地址
	for (int i = 0; i < 4; i++)  //可以通过p来访问a数组中的元素
		cout << *(p + i) << endl;

默认情况下,函数的链接性为外部的,除非加了关键字static,则表示该函数链接性是内部的。



全局变量和静态作用域变量都是在程序中定义的变量,它们的作用范围和生命周期与局部变量有所不同,但在实际应用中有着各自的特和用途。 ### 全局变量 全局变量是在整个程序范围内都可见的一个变量,意味着从任何函数都可以访问并修改其值。这意味着一旦在一个函数里对全局变量进行了更改,那么在程序的其他任何地方都会看到这种改变。 **优点**: - 提供了全局的共享数据,便于在不同函数间传递信息。 - 可以减少函数间的复杂通信需求。 **缺点**: - 过度依赖全局变量可能导致代码难以理解及维护,增加错误的可能。 - 存在命名冲突的风险,尤其是在大型项目中,可能会有多个部分同时引用同名全局变量而造成混乱。 ### 静态作用域变量 静态作用域变量是语言特之一,用于限定变量作用域仅限于包含该变量的最外层代码块(例如 `{}` 中的内容),尽管它的名称可能是全局的(例如,在 C/C++ 中使用 `static` 关键字在函数内部定义的变量)。这样的设计使得静态作用域变量能够保留其值之间的关联,即使函数调用结束后再次调用也依然有效。 **特点**: - 持久:在每次函数调用后仍保持其值,直到程序终止或明确销毁。 - 局部作用域:只在创建它的代码块中可用,但拥有持久状态。 **应用场景**: - 用于记录某些状态,如计数器、统计等,需要在整个程序执行期间持续跟踪的情况。 - 作为临时存储的容器,避免频繁地在函数之间传递大量的数据。 ### 相关问题: 1. **如何在多线程环境下管理全局变量的安全?** 当多个线程尝试同时访问或修改全局变量时,容易引发竞态条件(race condition),导致不可预测的行为。为此,可以采用锁机制、原子操作或其他并发控制策略来保护全局变量,确保在同一时间只有一个线程能访问或修改它。 2. **在使用静态作用域变量时,如何避免内存泄露的问题?** 静态作用域变量通常不会引起内存泄露,因为它们的生存期与代码块的生存期一致。不过,如果你错误地假设了一个静态作用域变量会自动释放内存(如未正确处理资源分配和释放的情况),则可能出现内存泄漏。确保所有动态分配的资源都在适当的位置被正确释放。 3. **何时应该选择全局变量而非静态作用域变量?** - 全局变量适合当程序需要在整个上下文中共享数据,而不需要考虑线程安全或其他复杂的并发问题。 - 静态作用域变量适用于需要持久化状态但又希望限制作用域在单一代码块内的情况,尤其当这些变量需要跨越函数调用边界保持状态连续时。 - 根据具体的程序需求和设计原则,选择合适的变量类型可以使程序更清晰、更容易维护。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值