C
C 语法

Storage-class specifiers

存储类说明符

指定对象和功能的存储时间链接

  • auto - 自动持续时间和不连接

_Thread_local - thread storage duration(since C11)

  • _Thread_local - 线程存储时间

(since C11)

说明

存储类说明符出现在声明中。最多可以使用一个说明符,除了_Thread_local可以结合staticextern调整结合(自C11以来)。存储类说明符确定它们声明的名称的两个独立属性:存储持续时间链接

1)auto说明符只允许在块范围声明的对象(函数参数列表除外)。它表示自动存储持续时间并且没有链接,这是这些类型的声明的默认值。

2)register说明符仅适用于在块范围声明的对象,包括函数参数列表。它指示自动存储持续时间并且没有链接(这是这些类型的声明的默认值),但是另外提示优化器在可能的情况下将该变量的值存储在CPU寄存器中。无论这种优化是否发生,声明的变量register都不能用作地址运算符的参数,不能使用alignas(因为C11),并且register数组不能用于指针转换。

3)static说明符同时指定静态存储持续时间(除非与_Thread_localC11组合)和内部链接(除非在块范围使用)。它可以与文件范围内的函数和文件和块范围内的变量一起使用,但不能在函数参数列表中使用。

4)extern说明符指定静态存储持续时间(除非与_Thread_localC11结合)和外部链接。它可以在文件和块范围中使用函数和对象声明(不包括函数参数列表)。如果extern在重新声明已经用内部链接声明的标识符时出现,则链接保持内部。否则(如果先前的声明是外部的,无关联的或不在范围内的话),该联系是外部的。

5)_Thread_local表示线程的存储时间。它不能用于函数声明。如果它用于对象的声明,则它必须出现在同一对象的每个声明中。如果它在块范围声明中使用,则必须将它与静态或外部结合来决定链接。(自C11以来)

如果未提供存储类说明符,则默认值为:

extern用于块范围内extern对象的文件范围auto对象的所有函数

对于使用存储类说明符声明的任何结构体或联合体,存储持续时间(但不是链接)以递归方式适用于其成员。

块范围的函数声明可以使用,extern或者根本不使用。文件范围的函数声明可以使用externstatic

函数参数不能使用除register。以外的任何存储类说明符。请注意,static在数组类型的函数参数中有特殊含义。

存储时间

每个对象都有一个称为存储时间的属性,这会限制对象的生存期。C中有四种存储持续时间:

  • 自动存储时间。当声明对象的块被输入时,存储器被分配,当通过任何方式(goto,return,end)结束时,存储器被分配。一个例外是VLA; 它们的存储在执行声明时分配,而不是在块入口处分配,并且当声明超出范围时,而不是在块退出时(自C99以来)释放。如果块是递归输入的,则为每个递归级别执行新的分配。所有函数参数和非static块范围对象都具有该存储持续时间以及块范围中使用的复合文字。

线程存储时间。存储持续时间是创建它的线程的整个执行过程,并且在线程启动时存储在该对象中的值将被初始化。每个线程都有自己独特的对象。如果执行访问此对象的表达式的线程不是执行其初始化的线程,则该行为是实现定义的。所有声明为_Thread_local的对象都有这个存储期限。(自C11以来)

  • 线程存储时间。存储持续时间是创建它的线程的整个执行过程,并且在线程启动时存储在该对象中的值将被初始化。每个线程都有自己独特的对象。如果执行访问此对象的表达式的线程不是执行其初始化的线程,则该行为是实现定义的。所有声明的对象_Thread_local都有这个存储时间。

(since C11)

  • 分配的存储时间。根据请求使用动态内存分配功能分配和解除分配存储空间。

连锁

连锁是指在其他范围内引用标识符(变量或函数)的能力。如果具有相同标识符的变量或函数在多个作用域中声明,但不能从所有作用域中引用,则会生成多个变量实例。以下联系被认可:

  • 没有联系。标识符只能从其所在的范围中引用。所有函数参数和所有非extern块范围变量(包括已声明的变量static)都具有此关联关系。

如果相同的标识符在同一翻译单元中同时出现内部和外部链接,则行为不确定。当使用临时定义时,这是可能的。

链接和库

具有外部链接的声明通常在头文件中可用,以便#include该文件的所有翻译单元可以引用与别处定义的相同的标识符。

出现在头文件中的任何带有内部链接的声明都会在包含该文件的每个翻译单元中生成一个独立且不同的对象。

库接口:

// flib.h #ifndef FLIB_H #define FLIB_H void f(void // function declaration with external linkage extern int state; // variable declaration with external linkage static const int size = 5; // definition of a read-only variable with internal linkage enum { MAX = 10 }; // constant definition inline int sum (int a, int b) { return a+b; } // inline function definition #endif // FLIB_H

库实现:

// flib.c #include "flib.h" static void local_f(int s) {} // definition with internal linkage (only used in this file) static int local_state; // definition with internal linkage (only used in this file) int state; // definition with external linkage (used by main.c) void f(void) {local_f(state} // definition with external linkage (used by main.c)

应用代码:

// main.c #include "flib.h" int main(void) { int x[MAX] = {size}; // uses the constant and the read-only variable state = 7; // modifies state in flib.c f( // calls f() in flib.c }

关键词

auto, register, static, extern, _Thread_local.

注意

关键字_Thread_local通常通过thread_local标题中定义的便利宏使用threads.h

typedef说明符在C语言语法中正式列为存储类说明符,但用于声明类型名称并且不指定存储。

文件范围中的名称在C中const没有extern外部链接(作为所有文件范围声明的默认链接),但是在C ++中是内部链接。

参考

  • C11 standard (ISO/IEC 9899:2011):