存储类说明符
指定对象和函数的存储期和链接
auto
- 自动存储期,无链接register
- 自动存储期,无链接;此变量的地址不能被获取static
- 静态存储期和内部链接(除非在块作用域内)extern
- 静态存储期和外部链接(除非已声明为内部链接)
|
(C11 起) |
目录 |
[编辑] 解释
存储类说明符出现在声明中和复合字面量表达式中(C23起)。最多可以使用一个说明符,但_Thread_local(C23前)thread_local(C23起)可以与static或extern结合以调整链接(C11起)。存储类说明符决定它们声明的名称的两个独立属性:存储期和链接。
_Alignas
(C23前)alignas
(C23起)(C11起),并且register数组不能转换为指针。
5) _Thread_local(C23前)thread_local(C23起)指示线程存储期。它不能用于函数声明。如果它用于对象声明,则它必须出现在同一对象的所有声明中。如果它用于块作用域声明,则它必须与static或extern结合以决定链接。 |
(C11 起) |
如果没有提供存储类说明符,则默认值是
- 所有函数都为extern
- 文件作用域的对象为extern
- 块作用域的对象为auto
对于使用存储类说明符声明的任何结构体或联合体,存储期(而非链接)递归地应用于其成员。
块作用域的函数声明可以使用extern或不使用。文件作用域的函数声明可以使用extern或static。
函数参数不能使用除register之外的任何存储类说明符。请注意,static在数组类型的函数参数中具有特殊含义。
[编辑] 存储期
每个对象都有一个名为存储期的属性,它限制了对象的生命周期。C中有四种存储期
- 自动存储期。当声明对象的块被进入时分配存储,并在通过任何方式(goto、return、到达末尾)退出时解除分配。一个例外是VLA;它们的存储在声明执行时分配,而不是在块进入时,并在声明超出作用域时解除分配,而不是在块退出时(C99起)。如果块被递归进入,则每个递归级别都会执行新的分配。所有函数参数和非static块作用域对象都具有此存储期,以及在块作用域中使用的复合字面量(C23前)
- 静态存储期。存储期是程序的整个执行过程,并且对象中存储的值只初始化一次,在main函数之前。所有声明为static的对象以及所有具有内部或外部链接但未声明为_Thread_local(C23前)thread_local(C23起)(C11起)的对象都具有此存储期。
|
(C11 起) |
- 分配存储期。使用动态内存分配函数,根据请求分配和解除分配存储。
[编辑] 链接
链接指的是标识符(变量或函数)在其他作用域中被引用的能力。如果一个具有相同标识符的变量或函数在多个作用域中声明,但不能从所有作用域中被引用,那么会生成该变量的多个实例。识别以下链接
- 无链接。变量或函数只能从其所在的作用域(块作用域)中引用。所有未声明为
extern
的块作用域变量,以及所有函数参数和所有非函数或变量的标识符都具有此链接。
- 无链接。变量或函数只能从其所在的作用域(块作用域)中引用。所有未声明为
- 内部链接。变量或函数可以从当前翻译单元中的所有作用域中引用。所有声明为
static
或constexpr
(C23起)的文件作用域变量都具有此链接,以及所有声明为static
的文件作用域函数(静态函数声明只允许在文件作用域)。
- 内部链接。变量或函数可以从当前翻译单元中的所有作用域中引用。所有声明为
- 外部链接。变量或函数可以从整个程序中的任何其他翻译单元中引用。所有未声明为
static
或constexpr
(C23起)的文件作用域变量都具有此链接,所有未声明为static
的文件作用域函数声明,所有块作用域函数声明,以及,如果之前没有可见的内部链接声明,所有声明为extern
的变量或函数都具有此链接。
- 外部链接。变量或函数可以从整个程序中的任何其他翻译单元中引用。所有未声明为
如果同一标识符在同一翻译单元中同时出现内部链接和外部链接,则行为是未定义的。这在使用了暂定定义时可能发生。
[编辑] 链接和库
本节不完整 原因:这应该作为c/language下“杂项”中的一个独立的顶级条目吗? |
具有外部链接的声明通常在头文件中提供,以便所有#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通常通过便利宏thread_local使用,该宏定义在头文件<threads.h>中。 |
(直至 C23) |
typedef
和constexpr
(C23起)说明符在C语言语法中形式上被列为存储类说明符,但它们不指定存储。
auto说明符也用于类型推断。 |
(自 C23 起) |
文件作用域中声明为const且不是extern的名称在C中具有外部链接(作为所有文件作用域声明的默认值),但在C++中具有内部链接。
[编辑] 示例
#include <stdio.h> #include <stdlib.h> // static storage duration int A; int main(void) { printf("&A = %p\n", (void*)&A); // automatic storage duration int A = 1; // hides global A printf("&A = %p\n", (void*)&A); // allocated storage duration int* ptr_1 = malloc(sizeof(int)); // start allocated storage duration printf("address of int in allocated memory = %p\n", (void*)ptr_1); free(ptr_1); // stop allocated storage duration }
可能的输出
&A = 0x600ae4 &A = 0x7ffefb064f5c address of int in allocated memory = 0x1f28c30
[编辑] 参考
- C23 标准 (ISO/IEC 9899:2024)
- 6.2.2 标识符的链接 (p: 35-36)
- 6.2.4 对象的存储期 (p: 36-37)
- 6.7.1 存储类说明符 (p: 97-100)
- C17 标准 (ISO/IEC 9899:2018)
- 6.2.2 标识符的链接 (p: 29-30)
- 6.2.4 对象的存储期 (p: 30)
- 6.7.1 存储类说明符 (p: 79)
- C11 标准 (ISO/IEC 9899:2011)
- 6.2.2 标识符的链接 (p: 36-37)
- 6.2.4 对象的存储期 (p: 38-39)
- 6.7.1 存储类说明符 (p: 109-110)
- C99 标准 (ISO/IEC 9899:1999)
- 6.2.2 标识符的链接 (p: 30-31)
- 6.2.4 对象的存储期 (p: 32)
- 6.7.1 存储类说明符 (p: 98-99)
- C89/C90 标准 (ISO/IEC 9899:1990)
- 3.1.2.2 标识符的链接
- 3.1.2.4 对象的存储期
- 3.5.1 存储类说明符
[编辑] 另请参阅
C++ 文档,关于存储类说明符
|