【C++基础】存储持续性、作用域、链接性

        为了方便开发者管理与修改,实现某个功能的C++程序可能由多个文件构成。常用的文件架构为:

1.头文件:存放原型,符号常量,内联函数实现;

2.函数源文件:存放有关函数的实现;

3.主程序源文件:利用函数和类实现某些功能;

        在将以上多个文件编译成可执行文件时,需要将上述多个文件组合成一个可执行文件,那么需要有关规则来规定,文件中名称的存在时间、可见范围(文件内与文件之间),从而正确完成编译。

图1 UNIX系统中的编译过程[1]

1.名词内涵

1.1存储持续性

定义:数据在内存中保留时间的长短,也即数据在程序中的生命周期,分为以下四种:

自动存储持续性:由系统自动管理。在执行名称所属的函数或者代码块时被创建,在执行完成后自动释放;

静态存储持续性:在程序运行期间都存在;

动态存储持续性:由用户自行管理分配和释放。(new 和 delete运算符的作用)。也被称为自由存储(free store)或堆(heap)

线程存储持续性:在多线程编程中会涉及,不同线程中的变量生命周期不同;

1.2作用域

定义:名称在一个文件内的可见范围,分为以下两种:

局部:只在定义名称的代码块中可见;

全局:在整个文件内都可见,也被成为文件作用域;

1.3链接性

定义:名称在不同文件之间的可见性,或共享性,分为以下两种:

内部:只能在文件内部的函数间共享;

外部:可以在不同文件之间共享;

无链接性:只能在代码块或函数中访问

2.各种名称/变量的特性

变量的存储持续性、作用域以及链接性通常是存在联系的

2.1自动变量

所谓自动变量,即在函数中声明的函数参数和无限定符的变量;

存储持续性:自动存储持续性;作用域:局部;链接性:无链接性;

1)在函数原型的括号中出现的变量名,只在函数参数列表内(也就是括号内)可见,所以变量名叫什么以及是否出现都不重要;

2)如果一个代码块内嵌套了另一个代码块(所谓代码块,即由大括号括起来的部分),嵌套代码块中的变量会屏蔽掉外层代码块的同名变量,包括全局变量;

3)编译器使用存储区中开辟了一个栈来维护自动变量;

2.2静态变量

静态变量的存储持续性是静态存储持续性,但是其作用域和链接性取决于变量声明的位置

外部链接性、全局:在代码块外部,即文件中声明,无修饰符

内部链接性、全局:在代码块外部,即文件中声明,并且使用关键字static修饰;

无链接性、局部:在代码块内部声明变量,并且使用关键字static修饰;

1)静态变量在程序运行开始就存在,直到程序结束后释放;

2)如果没有显式初始化,则静态变量默认初始化为0。如果初始化时没有足够的信息(例如调用了函数),则需要在链接完成后动态初始化;

3)编译器在存储区中开辟了一个静态存储区存放所有静态变量;

4)单定义规则(One Definition Rule):

        变量只能有一次定义。定义意味着初始化,系统会为其分配内存;

图2 五种变量存储方式[1]

2.2.1外部链接性、全局变量

1)需要在一个文件定义该变量,变量被定义后,可以在这个文件中该变量后面任何位置使用它;

2)如果其他文件需要使用该变量,则需要声明该变量,声明时用extern关键字修饰;

将1)、2)总结为一个定义,多个声明;

3)初始化也可以使用extern关键字修饰,但是效果与不使用相当;

4)为了防止内部同名变量屏蔽全局变量,可以使用作用域解析符来指出变量;

2.2.2内部链接性、全局变量

        使用static修饰的内部链接性、全局变量,会屏蔽同名的外部链接性、全局变量;

2.2.3无链接性、局部变量

        这种类型的变量通常用于函数内部中,不想每次进入函数都被初始化的变量。可以实现某些特定功能,比如,记录函数被调用的次数。

3.限定符

3.1volatile限定符

        该限定符说明变量在程序没有对其进行修改的情况下,内存中的数据也可能会发生改变。上述情况通常发生在内存地址为某硬件输入端口时。

        在不使用volatile限定符时,如果程序在没有对变量修改的情况下,多次使用该变量,编译器会进行优化操作,不会重复读取内存,而是直接将数据放入寄存器。

        使用volatile限定符,则向编译器表明不需要此优化,每次使用该变量都向内存读取。

3.2mutable限定符

        在类或者结构声明中使用,表明某个变量是可以修改的。即使在初始化结构或类时,使用了const关键字。

3.3const限定符

1)使用const限定符修饰变量,表明该变量是不允许被修改,等价于常量;

2)在文件中所有代码块外,只有const限定符,没有extern限定符修饰的全局变量,链接性是内部的,其对于其他文件不可见。此举可以方便在头文件中使用例如 const int pi = 3.14 的语句,然后在其他文件都包含该头文件是不会出错;

3)同时有extern 和 const 修饰的变量,其链接性为外部;

4.名称空间

        除了利用以上C++作用域规则外,C++还提供了名称空间工具,来解决程序中可能出现的名称相同而导致的冲突问题。

1)使用关键字 namespace 可以创建一个名称空间,不同命名空间里相同的名称不会冲突;

2)命名空间可以嵌套,但是不能位于代码块中;

3)全局命名空间:对应于全局变量所在的空间;

4)可以将变量加入到已有的命名空间中;

5)使用 using 声明,如 using std::cout,将 命名空间 std 中的 名称 cout 暴露在当前代码

      块,或是当前文件中,作用域范围取决于 using 声明的位置;

6)使用using namespace 编译指令,使命名空间中的所有名称暴露;

7)使用using namespace 编译指令,如果当前作用域内有存在同名,那么 using 命名空间中的名称将被隐藏;

8)不能使用using 声明来暴露一个在当前代码块中已经使用过的名称;

参考文献

[1] Prata S. C++ Primer Plus[M]. 2002 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值