概念
链接属性
linkage,链接属性是描述链接器应如何链接变量的属性。链接属性决定某变量是否可供另一个文件使用,或者是否只在声明它的文件中使用
-
外部链接属性
- 本编译单元中有外部链接属性的变量/函数可被所有其他编译单元访问
- 其内存通常在程序启动前的加载阶段被分配 -
内部链接属性
- 其他编译单元不可访问本编译单元中有内部链接属性的变量/函数
- 仅当变量具有全局作用域时才能实现内部链接
- 静态全局变量、常量全局变量为内部链接
- 顶级名字空间范围(C中的文件范围)中被const而不是extern修饰的变量在C中具有外部链接,但在C++中具有内部链接
- 其内存通常在程序启动前的加载阶段被分配
生存期
storage duration,存储持续时间。与变量保存位置相关,变量从被分配内存,到释放其占用的内存。具体可参考Linux 进程内存分布
-
自动存储持续时间
- 举例如普通局部变量 -
静态存储持续时间
- 在程序开始时分配对象的存储空间,在程序结束时释放对象的存储空间
- 只有一个实例
- 举例
- 在名字空间范围内声明的所有对象(包括全局名称空间)
- 使用static或extern声明的对象 -
线程存储持续时间
- 对象的存储在线程开始时分配,并在线程结束时释放
- 每个线程都有其自己的对象实例
- 举例如声明为thread_local的对象 -
动态存储持续时间
- 通过使用动态内存分配功能,可以按请求分配和释放对象的存储
作用域
scope,有效范围,这是一个在编译阶段的概念。例如代码中的变量或函数,有的可以在整个程序中的所有范围内起作用,这称为“全局”的变量或函数;有的只能在一定的范围内起作用,称为“局部”变量。
可见性
当作用域发生嵌套,并且内层的变量和外层的变量同名时,在内层里,外层的变量暂时地失去了可见性
存储类说明符
static
仅在对象声明(函数参数列表中除外),函数声明(块范围中除外)和匿名联合的声明中才允许使用static说明符
-
类成员的声明中使用
- 声明一个静态成员 -
在对象声明时使用(不包括带有thread_local)
- 指定静态存储持续时间 -
在命名空间范围的声明中使用
- 指定内部链接
extern
仅在变量和函数的声明中(类成员或函数参数除外)允许使用extern说明符
- 指定外部链接
- 不影响存储持续时间,但是不能在自动存储持续时间对象的定义中使用它,因此所有被extern修饰的对象都具有静态或线程持续时间
- 使用extern并且没有初始化程序的变量仅仅是声明,而不是定义
thread_local
仅在命名空间范围内声明的对象,在块范围内声明的对象和静态数据成员才允许使用thread_local说明符。使用thread_local说明符声明的变量仅可在它在其上创建的线程上访问。 变量在创建线程时创建,并在销毁线程时销毁。 每个线程都有其自己的变量副本。
- 指示对象具有线程存储持续时间
- 可以将其与static或extern组合以分别指定内部或外部链接(始终具有外部链接的静态数据成员除外),但是附加的static不会影响存储时间
- 在块范围内被thread_local修饰变量,隐式地也被static修饰
使用场景:
-
全局thread_local变量
- 在被访问之前,按照声明/定义语句执行初始化
- 如果不访问则不会被初始化
- 举例如:声明/定义某个复杂类型,多个线程中进行访问而互不影响;并且单个线程只在线程启动后(访问thread_local变量前)对thread_local变量进行初始化一次 -
局部thread_local变量
- 即在块范围内声明/定义的thread_local变量,其同时被隐式的声明为static,当代码经过其声明/定义语句时进行初始化,并且只会初始化一次
- 举例如:某个操作内部需要初始化一个复杂类型,有多个线程并发重复的执行这个操作。将这个复杂类型实例声明/定义为局部thread_local变量可以实现多个线程中的复杂类型实例互相隔离;并且单个线程重复执行这个操作时,只初始化复杂类型实例一次
mutable
register
静态局部变量
- 在块范围内使用static或thread_local说明符声明的变量具有静态或线程存储期限
- 如果多个线程尝试同时初始化同一静态局部变量,则初始化仅发生一次
参考
Storage class specifiers
Internal Linkage and External Linkage in C