作用域、存储期和链接摘要
本节阅读量:作用域、存储期和链接的概念导致了许多混乱,因此我们将额外上一课来总结所有内容。其中一些内容我们还没有介绍,它们在这里只是为了以后的完整性/参考。
作用域摘要
标识符的作用域确定可以在源代码中访问标识符的位置。
- 具有块(局部)作用域的变量只能从声明点访问,直到声明它们的块(包括嵌套块)的末尾。这包括:
- 局部变量
- 函数参数
- 代码块中类型定义(例如enum和class)
- 具有全局作用域的变量和函数可以从声明点访问,直到文件结束。这包括:
- 全局变量
- 函数
- 命名空间(全局或非全局)中类型定义(例如enum和class)
存储期摘要
变量的存储期决定了它的创建和销毁时间。
- 具有自动存储期的变量在定义点创建,并在退出它们所属的块时销毁。这包括:
- 局部变量
- 函数参数
- 具有静态存储期的变量在程序开始时创建,在程序结束时销毁。这包括:
- 全局变量
- 静态局部变量
- 具有动态存储期的变量由程序员请求创建和销毁。这包括:
- 动态创建的变量
链接摘要
标识符的链接属性确定标识符的多个声明是否引用同一实体(对象、函数、引用等)。
- 没有链接的标识符意味着该标识符仅引用其自身。这包括:
- 局部变量
- 代码块中类型定义(例如enum和class)
- 具有内部链接的标识符可以在其声明的文件中的任何位置访问。这包括:
- Static 全局变量
- Static 函数
- Const 全局变量
- 在未命名的命名空间中声明的函数
- 在未命名的命名空间中类型定义(例如enum和class)
- 具有外部链接的标识符可以在其声明的文件或其他文件中的任何位置访问(通过前向声明)。这包括:
- 函数
- 非常量全局变量
- Extern const 全局变量
- Inline const 全局变量
如果将定义编译到多个.cpp文件中,则具有外部链接的标识符通常会导致重复定义的链接器错误(由于违反了单定义规则)。这个规则有一些例外(对于类型、模板和内联函数和变量)——在对应的课程中有相应的说明。
另请注意,默认情况下,函数具有外部链接。可以使用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; | 必须未初始化 |
Const 变量前向声明 | extern const int g_x; | 必须未初始化 |
Constexpr 变量前向声明 | extern constexpr int g_x; | 不允许 |
什么是存储类说明符?
当用作标识符声明的一部分时,static 和extern 关键字称为存储类说明符(storage class specifiers)。在这种情况下,它们设置标识符的存储期和链接属性。
C++现支持4个存储类说明符:
关键字 | 含义 | 注 |
---|---|---|
extern | 静态 (或 thread_local) 存储期,外部链接 | |
static | 静态 (或 thread_local) 存储期,内部链接 | |
thread_local | 线程 存储期 | |
mutable | 即使所在对象是const,但标识的字段,仍然可被修改 | |
auto | 自动存储期 | C++11 废弃 |
register | 自动存储期,并暗示编译器将这个对象保存在寄存器内 | C++17 废弃 |
术语存储类说明符通常仅在正式文档中使用。
