[C++]存储连续性、作用域和链接属性总结

1 存储连续性(生存周期)

C++提供四种数据存储连续性,用以规定变量的生存周期。
1.自动存储连续性:在函数中声明定义的变量(包括形参),在函数调用时初始化,在函数返回时销毁。
2.静态存储连续性:在程序的整个运行周期内一直存在。
3.动态存储连续性:用new运算符申请的内存将一直存在,直到手动的调用delete回收内存。
4.线程存储连续性:C++11标准引入的新的存储连续性,变量的生存周期即线程的运行周期。

2 作用域(可用范围)

变量在文件中的可见范围,分局部可见和全局可见。

作用域为局部的变量只在定义它的代码块中可用,例如自动变量。静态变量的作用域是全局还是局部取决于其定义方法。类中声明的成员变量的作用域是整个类。名称空间中定义的变量的作用域就是整个名称空间。

C++11标准开始,auto关键字用于变量的类型推断,而这之前,auto是指变量具有自动存储连续性的意思。

3 链接属性(在文件之间的可用范围)

具有静态持续性的变量,在程序的整个运行周期内有效,具有链接属性,分外部、内部和无链接性,外部链接的变量在其他文件中可见,内部链接属性的变量则只在本文件中可见,无链接属性的变量则只能在当前代码块中可见。

要想创建链接性为外部的静态持续变量,那么必须在代码块的外面声明它们;

要想创建链接性为外部的静态持续变量,那么必须在代码块的外面声明它们且加上static限定符;

要想创建无链接性的静态持续变量,那么必须在代码块内声明它们且加上static限定符;

静态变量的数目在程序的运行期内是固定的,因此不需要编译器增加栈来管理它们,而是分配固定的内存用于存放静态白能量。还有就是,如果静态变量在声明的时候没有显示的初始化,那么编译器会给它赋一个初值。

几种变量存储方式
 持续性作用域链接性如何声明
自动自动代码块代码块中
静态,无链接性静态代码块代码块中,带关键字static
静态,外部链接性静态文件外部不在任何函数内
静态,内部链接性静态文件内部不在任何函数内,带关键字static

4 存储区(在内存中存放的位置)

C++的数据存储区分为以下几种:堆(自由存储区):动态分配的;栈:系统自动申请和释放的;静态存储区:在程序整个运行期间都存在的;常量存储区:存放常量的;代码区:存放代码序列的。

存储区和存储连续性的联系,实际上两者关注的概念就不一样,在我看来可以说两者没有联系了,前者是内存的分配方式,相应的变量要存储到相应的位置,存储连续性关注的是在程序的运行过程中,变量的生存时间长短。联系大概是:栈中的变量具有自动存储连续性,自由存储区中的变量具有动态存储连续性,静态区中的变量具有静态存储连续性,但这种联系又不是严谨的,比如常量分局部常量和全局常量,那么它就有可能具有静态存储连续性或者自动存储连续性。

倒是堆和自由区的区别有必要区分一下,两者真的没有任何区别吗?参考:堆和自由存储区的区别

几种静态变量

静态变量根据连接属性的不同可以分成三种:局部静态变量、外部不可引用的全局静态变量、外部可以引用的全局变量

1.局部静态变量(存储在静态存储区,作用域为代码块,无链接性)

有时希望函数中的局部变量的值在函数调用结束后不消失而保留原值,在下一次该函数调用时,该变量保留上一次函数调用结束时的值,这时就应该通过static关键字将代码块中的变量声明为静态局部变量。

1)静态局部变量存储在静态存储区,在程序整个运行期间都不释放。其他局部变量存储在栈上,函数调用结束后即释放。

2)在程序运行时它已有初值,以后每次调用函数时不再重新赋初值而只是保留上次函数调用结束时的值。其他局部变量在函数调用时进行赋值,每调用一次函数重新赋一次初值。

3)如果在定义局部变量时不赋初值的话,对静态局部变量来说,编译时自动赋初值0(对数值型变量) 或空字符(对字符型变量)。而其他变量如果不赋初值,则它的值是一个不确定的值。这是由于每次函数调用结束后存储单元已释放,下次调用时又重新另分配存储单元,而所分配的单元中的值是不确定的。

4)虽然静态局部变量在函数调用结束后仍然存在,但其他函数是不能引用它的,也就是说它的作用域是局部的,其他文件也不可以访问它,它是没有链接性的。

#include <iostream>
using namespace std;

int func(int n)
{
    static int x = 1; //只会在编译时赋初值1一次,下次调用函数x的值就是自己的值而不发生重新赋值
    return x *= n;
}

int main()
{
    for(int i = 1; i < 6; i++) {
        cout << “func(” << i << ") = " << func(i) << endl;
    }

    return 0;
}

运行结果: 

2. 全局变量(存储在静态存储区,作用域为文件,外部链接性)

外部变量是在函数的外部定义的,它的作用域为从变量的定义处到文件末尾。第一种外部变量为不加static关键字限制的变量,具有外部链接性,外部文件可以访问。

int global = 10; //初始化的全局变量(静态变量),外部文件可以引用,但需要通过extern关键字声明
int func() {
	...
}

1. 在同一文件内声明

如果在定义之前的函数想引用全局变量,则应该在引用之前用关键字extern对该变量进行声明,有了此声明,就可以从声明处起,合法地引用该全局变量,这种声明称为提前引用声明。

2. 在外部文件中声明

外部文件想正确的引用某个静态变量,正确的做法是使用extern对变量作外部变量声明。

main.cpp

double global = 3.5; //全局变量

void update(double param);

int main() {
	cout << "global = " << global << '\n';
	update(0.1);
	cout << "global = " << global << '\n';

	return 0;
}

helper.cpp 

extern double global; //声明外部变量

void update(double param) {
	global += param;
	cout << "global update to " << global << '\n';
}

3.全局静态变量(存储在静态存储区,作用域为文件,内部连接属性)

有时在程序设计中希望某些外部变量只限于被本文件引用,而不能被其他文件引用,这时可以在定义外部变量时加一个static声明。

static int this_file = 10; //初始化的全局变量(静态变量),外部文件不可以引用,仅限本文件访问
int func() {
	...
}

例子,程序包含main.cpp和helper.cpp两个文件。

main.cpp

int x = 10;
int y = 20;
int static z = 30;

void helper();

int main() 
{
	cout << "x的地址: " << &x << '\n';
	cout << "y的地址: " << &y << '\n';
	cout << "z的地址: " << &z << '\n';
	helper();

	system("pause");
	return 0;
}

helper.cpp

extern int x;
static int y = 40;
int z = 50;

void helper() {
	cout << "helper - x的地址: " << &x << '\n';
	cout << "helper - y的地址: " << &y << '\n';
	cout << "helper - z的地址: " << &z << '\n';
}

运行结果显示,两个文件操作的变量x是同一个,y和z却是不同的变量。

注意:全局变量和静态变量的区别又是什么呢,我的理解是,全局变量也存储在静态区,也具有静态连续性,所以你可以说它是静态的,但这貌似又不符合静态的定义,另外静态变量不一定是全局的,因为static关键字可以修饰局部变量。上文中提到全局变量全局static变量,实际上代表着两种链接性,如果程序只有一个文件,那么两者在使用上是没有区别的。我们日常所谓的静态变量就是指static变量,全局变量概念更广,不必刻意区分二者。

静态的概念

到了这里,我想做一下静态这一概念的总结,简而言之,程序中有一部分变量是静态的,有以下几个特点:

1. 静态变量在程序的运行周期内一直存在

2. 静态变量的数目在程序运行过程中一直不变

3. 在编译时编译器负责为其分配静态存储区空间

4. 值是可改变的(当然可以选择加关键字声明成常量,但常量又是另外一个概念了)

5. 代码中没有显示初始化的静态变量,由编译器负责初始化工作,也是唯一一次初始化

函数的连续性和链接性

所有函数的持续性都是静态的,即在整个程序的执行期间一直存在,且默认情况下链接性为外部,既外部文件可以引用,除非使用static加以限制,声明为仅对本文件可见的函数。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值