6.11 - 作用域和链接小结
作用域、持续时间和链接这些概念很绕人,所以我们利用这节课对它们进行一次整理和总结。有些内容我们还没有介绍,但是我们仍然将其罗列在这里,在后续学习时可以进行参考。
作用域小结
变量标识符的作用域决定了标识符在哪里可以被访问。
- 具有块(局部)作用域的标识符,只能够在声明它们的块(及其嵌套块)中访问,这些变量包括:
- 具有文件(全局)作用域 的变量和函数从声明位置开始,直到文件结尾都可以被访问, 包括:
- 全局变量
- 函数
- 定义在全局作用域或命名空间中的用户自定义类型(包括枚举和类)
持续时间小结
变量的持续时间决定了它合适被创建和销毁。
- 具有自动存储持续时间的变量,在定义时被创建,而且在离开语句块时被销毁,包括:
- 具有静态存储持续时间的变量,在程序开始时创建,在程序结束时销毁,包括:
- 具有动态存储持续时间时间的变量在可以根据程序员的需要创建和销毁,包括:
- 动态分配的变量
链接小结
标识符的链接属性,决定了标识符的多个声明是否被看做同一个表示符。
- 不具备链接属性的标识符,意味着该标识符只表示它自己,包括:
- 局部变量
- 定义在块中的用户自定义类型(包括枚举和类)
- 具备内部链接属性**的标识符可以在文件内部的任何位置被访问,包括:
- 静态全局变量(初始化或未初始化的)
- 静态(
static
)函数 - const 全局变量
- 定义在匿名命名空间中的函数
- 定义在匿名命名空间中的用户自定义类型(包括枚举和类)
- 具备外部链接属性的标识符可以在定义它的文件中访问,也可以在其他文件中(通过前向声明)访问,包括:
- 函数
- 非常量全局变量(初始化或未初始化的)
- 外部常量全局变量
- 内联常量全局变量
- 定义在命名空间或全局作用域中的用户自定义类型(包括枚举和类)
具有外部链接的标识号如果在多个cpp文件中被编译,则会导致链接器报错(因为违反了单一定义规则(one-definition-rule))。不过,也有例外的情况(对于类型、目标、内联函数和内联变量)——我们会在后续的课程中介绍相关内容。
同时,注意函数默认具有外部链接,必须要使用 static
才能使其具有内部链接。
变量作用域、持续时间和链接小结
因为变量具有作用域、持续时间和链接属性,这里我们使用表格对其进行总结:
类型 | 例子 | 作用域 | 持续时间 | 链接属性 | 备注 |
---|---|---|---|---|---|
局部变量 | int x; |
块 | 自动 | 无 | |
静态局部变量 | static int s_x; |
块 | 静态 | 无 | |
动态变量 | int *x { new int{} }; |
块 | 动态 | 无 | |
函数形参 | void foo(int x) |
块 | 自动 | 无 | |
外部非常量全局变量 | int g_x; |
文件 | 静态 | 外部 | 初始化或未初始化 |
内部非常量全局变量 | static int g_x; |
文件 | 静态 | 内部 | 初始化或未初始化 |
内部常量全局变量 | constexpr int g_x { 1 }; |
文件 | 静态 | 内部 | 必须初始化 |
外部常量全局变量 | extern const int g_x { 1 }; |
文件 | 静态 | 外部 | 必须初始化 |
内联常量全局变量(C++17) | inline constexpr int g_x { 1 }; |
文件 | 静态 | 外部 | 必须初始化 |
前向声明小结
使用前向声明可以从其他文件中访问一个函数或者变量。声明变量的作用域与往常一样(全局变量具有文件作用域,局部变量具有块作用域)。
类型 | 例子 | 备注 |
---|---|---|
函数前向声明 | void foo(int x); |
只需要函数原型,不能有函数体 |
非常量的变量前向声明 | extern int g_x; |
必须未初始化 |
常量的前向声明 | extern const int g_x; |
必须未初始化 |
Constexpr 变量前向声明 |
extern constexpr int g_x; |
不允许,constexpr 不能前向声明 |
存储类型说明符到底是什么?
当 static
和 extern
关键字(存储类型说明符)作为变量声明的一部分时,它们可以设定标识符的存储持续时间和链接属性。
C++ 支持 4 种存储类型说明符:
说明符 | 含义 | 备注 |
---|---|---|
extern |
static (或 thread_local) 存储持续时间和外部链接 | |
static |
static (或 thread_local) 存储持续时间和内部链接 | |
thread_local |
thread 存储持续时间 | |
mutable |
即使类是const类型的,变量也允许修改 | |
auto |
自动存储持续时间 | 在 C++11 中已经弃用 |
register |
自动存储持续时间并且提示编译器将其存放在寄存器中 | 在 C++17 中已经弃用 |
术语 存储类型说明符 通常只会在正式的文档中使用。