存储类说明符
指定对象和函数的存储期(storage duration)和链接(linkage):
auto
- 自动存储期与无链接register
- 自动存储期与无链接;不能取这种对象的地址static
- 静态存储期与内部链接(除非在块作用域)extern
- 静态存储期与外部链接(除非已声明带内部链接)
|
(C11 起) |
解释
存储类说明符出现于声明和复合字面量表达式 (C23 起)中。至多可使用一个说明符,但可以将 _Thread_local (C23 前)thread_local (C23 起) 与 static 或 extern 组合以调整链接 (C11 起)。存储类说明符确定其所声明的名称的两个独立属性:存储期与链接。
5) _Thread_local (C23 前)thread_local (C23 起) 指示线程存储期。它不能用于函数声明。若将它用在对象声明上,则它必须在同一对象的每次声明上都存在。若将它用在块作用域声明上,则必须与 static 或 extern 之一组合以决定链接。
|
(C11 起) |
若不提供存储类说明符,则默认为:
- 对所有函数为 extern
- 对在文件作用域的对象为 extern
- 对在块作用域的对象为 auto
对于任何用存储类说明符声明的结构体或联合体,存储期(但非链接)递归地应用到其成员。
在块作用域的函数声明可以使用 extern 或完全不使用存储类说明符。在文件作用域的函数声明可以使用 extern 或 static。
函数形参不能使用除 register 以外的存储类说明符。注意 static 在数组类型的函数形参中有特殊含义。
存储期
每个对象都有称为存储期的属性,它限制对象的生存期。C 中有四种存储期:
- 静态存储期。存储期是整个程序的执行过程,只在
main
函数之前初始化一次存储于对象的值。所有声明为 static 对象和所有带内部或外部链接且不声明为 _Thread_local (C23 前)thread_local (C23 起) (C11 起) 的对象都拥有此存储期。
- 静态存储期。存储期是整个程序的执行过程,只在
|
(C11 起) |
- 分配存储期。按照请求,用动态内存分配函数分配和解分配存储。
链接
链接指的是标识符(变量或函数)可从其他作用域指代的能力。若在数个作用域中声明有同一标识符的变量或函数,但不能从所有这些作用域指代它们,则会创建变量的多个实例。可识别下列几种链接:
- 无链接。只能从其所在的作用域指代该标识符。所有函数形参和所有非 extern 的块作用域变量(包含声明为 static 者)都拥有此链接。
- 内部链接。能从当前翻译单元的所有作用域指代该标识符。所有 static 文件作用域标识符(函数和变量)都拥有此链接。
- 外部链接。能从整个程序的任何其他翻译单元指代该标识符。所有非 static 函数、所有 extern 变量(除非之前声明为 static)和所有文件作用域的非 static 变量都拥有此链接。
若同一标识符在同一翻译单元中一同带内部和外部链接出现,则行为未定义。这在使用试探性定义时有可能发生。
链接与库
本节未完成 原因:这或许应该为 c/language 中杂项下的顶层条目? |
带外部链接的声明常在头文件中可用,这使得所有 #include 了该头文件的翻译单元都可以指代定义于别处的相同标识符。
任何出现于头文件中的带内部链接的声明,在每个包含该文件的翻译单元中产生一个分离而独立的对象。
库接口,头文件“flib.h”: #ifndef FLIB_H #define FLIB_H void f(void); // 带外部链接的函数声明 extern int state; // 带外部链接的变量声明 static const int size = 5; // 带内部链接的只读对象定义 enum { MAX = 10 }; // 常量定义 inline int sum (int a, int b) { return a + b; } // inline 函数定义 #endif // FLIB_H 库实现,源文件“flib.c”: #include "flib.h" static void local_f(int s) {} // 带内部链接的定义(只用于此文件) static int local_state; // 带内部链接的定义(只用于此文件) int state; // 带外部链接的定义( main.c 使用) void f(void) { local_f(state); } // 带外部链接的定义( main.c 使用) 应用代码,源文件“main.c”: #include "flib.h" int main(void) { int x[MAX] = {size}; // 使用常量和只读变量 state = 7; // 修改 flib.c 中的 state f(); // 调用 flib.c 中的 f() } |
关键词
auto, register, static, extern, _Thread_local thread_local
注解
一般通过定义于头文件 <threads.h> 的便利宏 thread_local 使用关键词 _Thread_local |
(C23 前) |
C 语言文法中,typedef
和 constexpr
(C23 起) 说明符在形式上列作存储类说明符,但并不指定存储。
auto 说明符还用于类型推断。 |
(C23 起) |
在文件作用域的 const 且非 extern 的名称在 C 中拥有外部链接(同所有文件作用域的默认情况),但在 C++ 中拥有内部链接。
示例
#include <stdio.h> #include <stdlib.h> // 静态存储期 int A; int main(void) { printf("&A = %p\n", (void*)&A); // 自动存储期 int A = 1; // 隐藏全局 A printf("&A = %p\n", (void*)&A); // 分配存储期 int *ptr_1 = malloc(sizeof(int)); // 开始分配存储期 printf("address of int in allocated memory = %p\n", (void*)ptr_1); free(ptr_1); // 停止分配存储期 }
可能的输出:
&A = 0x600ae4 &A = 0x7ffefb064f5c address of int in allocated memory = 0x1f28c30
引用
- C23 标准(ISO/IEC 9899:2024):
- 6.2.2 Linkages of identifiers (第 35-36 页)
- 6.2.4 Storage durations of objects (第 36-37 页)
- 6.7.1 Storage-class specifiers (第 97-100 页)
- C17 标准(ISO/IEC 9899:2018):
- 6.2.2 Linkages of identifiers (第 29-30 页)
- 6.2.4 Storage durations of objects (第 30 页)
- 6.7.1 Storage-class specifiers (第 79 页)
- C11 标准(ISO/IEC 9899:2011):
- 6.2.2 Linkages of identifiers (第 36-37 页)
- 6.2.4 Storage durations of objects (第 38-39 页)
- 6.7.1 Storage-class specifiers (第 109-110 页)
- C99 标准(ISO/IEC 9899:1999):
- 6.2.2 Linkages of identifiers (第 30-31 页)
- 6.2.4 Storage durations of objects (第 32 页)
- 6.7.1 Storage-class specifiers (第 98-99 页)
- C89/C90 标准(ISO/IEC 9899:1990):
- 3.1.2.2 Linkages of identifiers
- 3.1.2.4 Storage durations of objects
- 3.5.1 Storage-class specifiers