C++内存模型-作用域和链接

作用域(scope)描述了在文件(翻译单元)的多大范围可见。

链接性(linkage)描述了名称如何在不同单元间共享。链接性为外部的名称可在文件间共享,链接性为内部的名称只能由一个文件中的函数共享。

 

(1)  自动变量只在包含它们的函数或代码块中可见。

//autoscp.cpp - 阐明自动变量的范围
#include<iostream>
void oil(int x);
int main()
{
	using namespace std;
	int texas = 31;
	int year = 2011;
	cout << "In main(), texas = " << texas << ", &texas = ";
	cout << &texas << endl;
	cout << "In main(), year = " << year << ", &year = ";
	cout << &year << endl;
	oil(texas);
	cout << "In main(), texas = " << texas << ", &texas = ";
	cout << &texas << endl;
	cout << "In main(), year = " << year << ", &year = ";
	cout << &year << endl;
	cin.get();
	return 0;
}
void oil(int x)
{
	using namespace std;
	int texas = 5;
	cout << "In oil(), texas = " << texas << ", &texas = ";
	cout << &texas << endl;
	cout << "In oil(),x = " << x << ", &x = ";
	cout << &x << endl;
	//开启一个板块
	{
		int texas = 113;
		cout << "In block, texas = " << texas;
		cout << ", &texas = " << &texas << endl;
		cout << "In block,x = " << x << ", &x = ";
		cout << &x << endl;
	}
	//板块结束
	cout << "post-block texas = " << texas;
	cout << ", &texas = " << &texas << endl;
}


当程序调用oil()时,这些变量仍留在内存中,但不可见。为两个新变量(x和texas)分配内存,从而使它们可见。 在程序执行到oil()中的内部代码块时,新的texas将不可见。当程序流程离开该代码块时,将释放最新的texas使用的内存,而第二个texas再次可见。当oil()函数结束时,texas和x都将过期,而最初的texas和year再次变得可见。

 

(2)  静态变量在整个程序执行期间一直存在。编译器分配固定的内存块来存储所有的静态变量。

与C语言一样,C++也为静态存储持续性变量提供了三种链接性:外部链接性(可在其他文件中访问)、内部链接性(只能在当前文件中访问)和无链接性(只能在当前函数或代码块中访问)。

1.     创建链接性为外部的静态持续变量:必须在代码块外面声明它;

2.     创建链接性为内部的静态持续变量:必须在代码块外面声明它,并使用static限定符;

3.     创建没有链接性的静态持续变量:必须在代码内声明它,并使用static限定符。

 

int global = 1000;           //静态持续,外部链接
static int one_file = 50;    //静态持续,内部链接
int main() {
	...
}
void func1(int n) {
	static int count = 0;    //静态持续,无链接性
	int llama = 0;
	...
}

 

 

5种变量存储方式

存储描述

持续性

作用域

链接性

如何声明

自动

自动

代码块

在代码块中

寄存器

自动

代码块

在代码块中,使用关键字register

静态,无链接性

静态

代码块

在代码块中,使用关键字static

静态,外部链接性

静态

文件

外部

不在任何函数内

静态,内部链接性

静态

文件

内部

不在任何函数内,使用关键字static

 

(3)  静态持续性、外部链接性

链接性为外部的变量通常简称为外部变量。 外部变量也称全局变量。

一方面,在每个使用外部变量的文件中,都必须声明它;另一方面,C++有“单定义规则”,该规则指出,变量只能有一次定义。

//external.cpp -- 外部变量
//与support.cpp一起编译
#include<iostream>
using namespace std;
//外部变量
double warming = 0.3;         //定义warming
//函数原型
void update(double dt);
void local();
int main()                    //使用全局变量
{
	cout << "Global warming is " << warming << " degrees.\n";
	update(0.1);              //调用函数更改warming
	cout << "Global warming is " << warming << " degrees.\n";
	local();                  //调用使用局部变量warming的函数
	cout << "Global warming is " << warming << " degrees.\n";
	cin.get();
	return 0;
}
//support.cpp -- 使用外部变量
//和external.cpp一起编译
#include<iostream>
extern double warming;   //使用另一个文件中的warming
//函数原型
void update(double dt);
void local();
using std::cout;
void update(double dt)    //修改全局变量
{
	extern double warming;   //可选的重声明
	warming += dt;           //使用全局变量warming
	cout << "Updating global warming to " << warming;
	cout << " degrees.\n";
}
void local()                //使用局部变量
{
	double warming = 0.8;   //新变量隐藏了外部变量
	cout << "Local warming = " << warming << " degrees.\n";
	//用作用域解析运算符访问全局变量
	cout << "But global warming = " << ::warming;
	cout << " degrees.\n";
}

1.     update( )修改了warming,这种修改在随后使用该变量时显现出来了。

2.     local( )函数表明,定义与全局变量同名的局部变量后,局部变量将隐藏全局变量。

3.     C++比C语言更进一步——它提供了作用域解析运算符(::)。 放在变量名前面时,该运算符表示使用变量的全局版本。

 

(4)  静态持续性,内部链接性。

static限定符用于作用域为整个文件的变量时,该变量的链接性将为内部的。

//file1
int errors = 20;      //外部声明
...

//file2
static int errors;    //仅对file2可用
void froobish()
{
	cout << errors;   //使用file2中定义的errors
	...
}

上述例子没有违反单定义规则,因为关键字static指出标识符errors的链接性为内部,因此并非要提供外部定义。

 

(5)  静态存储持续性、无链接性

//static.cpp -- 使用一个静态局部变量
#include<iostream>
//常数
const int ArSize = 10;
//函数原型
void strcount(const char * str);
int main()
{
	using namespace std;
	char input[ArSize];
	char next;
	cout << "Enter a line:\n";
	cin.get(input, ArSize);
	while (cin)
	{
		cin.get(next);
		while (next != '\n')       //如果next是换行符,则说明cin.get(input, ArSize)读取了整行
			cin.get(next);         //否则说明行中还有字符没被读取,使用一个循环丢弃余下的字符
		strcount(input);
		cout << "Enter next line (empty line to quit):\n";
		cin.get(input, ArSize);    //试图使用get(char *,int)来读取空行将导致cin为false
	}
	cout << "Bye\n";
	cin.get();
	return 0;
}
void strcount(const char * str)
{
	using namespace std;
	static int total = 0;         //静态局部变量
	int count = 0;                //自动局部变量
	cout << "\"" << str << "\"contains ";
	while (*str++)                 //直到字符串结尾
		count++;
	total += count;
	cout << count << " characters\n";
	cout << total << " characters total\n";
}

1.     由于数组长度为10,因此程序从每行读取的字符数都不超过9个。

2.     每次函数被调用时,自动变量count都被重置为0;然而,静态变量total只在程序运行时被设置为0,以后在两次函数调用之间,其值将保持不变,因此能够记录读取的字符总数。

 

(6)  函数和链接性

C/C++中所有函数的存储持续性都自动为静态的,即在整个程序执行期间都一直存在。在默认情况下,函数的链接性为外部的,即在文件间共享。实际上,还可以使用关键字static将函数的链接性设置为内部的,使之只能在一个文件中使用。必须同时在原型和函数定义中使用static关键字。

这意味着该函数只在这个文件中可见,还意味着可以在其他文件中定义同名的函数。 和变量一样,在定义静态函数的文件中,静态函数将覆盖外部定义,因此即使在外部定义了同名的函数,该文件仍将使用静态函数。

 


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值