C 参考手册
- C 语言
 - C 的历史
 - 基本概念
 - 表达式
 - 声明
 - 初始化
 - 函数
 - 语句
 - 静态断言
 - 字符常量
 - 函数声明
 - 函数定义
 - 转义序列
 - 翻译阶段
 - 标识符
 - 作用域
 - 生存期
 - 查找与命名空间
 - ASCII 码表
 - 类型
 - 遵从性
 - 算术类型
 - restrict 类型限定符
 - 类型
 - 对象与对齐
 - 主函数
 - 未定义行为
 - 内存模型
 - if 语句
 - switch 语句
 - for 循环
 - while 循环
 - do-while 循环
 - continue语句
 - break 语句
 - goto语句
 - return 语句
 - 值类别
 - 求值顺序
 - 整数常量
 - 浮点常量
 - 字符串字面量
 - 复合字面量
 - 常量表达式
 - 隐式转换
 - 成员访问运算符
 - 逻辑运算符
 - 比较运算符
 - 算术运算符
 - 赋值运算符
 - 自增/自减运算符
 - 其他运算符
 - sizeof 运算符
 - _Alignof 运算符
 - 转型运算符
 - C 运算符优先级
 - 泛型选择
 - 标量初始化
 - 数组初始化
 - 结构体与联合体初始化
 - 指针声明
 - 数组声明
 - 枚举
 - 存储类指定符
 - const 类型限定符
 - volatile 类型限定符
 - 结构体声明
 - 联合体声明
 - 位域
 - _Alignas
 - typedef 声明
 - 原子类型
 - 外部及试探性定义
 - inline 函数指定符
 - _Noreturn 函数指定符
 - 变长参数
 - 内联汇编
 - 可分析性
 - 替用运算符及记号
 - C 关键词
 - 预处理器
 - C 标准库头文件
 - 类型支持
 - 程序支持工具
 - 变参数函数
 - 错误处理
 - 动态内存管理
 - 日期和时间工具
 - 字符串库
 - 算法
 - 数值
 - 文件输入/输出
 - 本地化支持
 - 原子操作库
 - 线程支持库
 - 实验性 C 标准库
 - 有用的资源
 - 符号索引
 - 注释
 
存储类指定符
指定对象和函数的存储期( storage duration )和链接( linkage ):
auto- 自动存储期与无链接register- 自动存储期与无链接;不能取这种对象的地址static- 静态存储期与内部链接(除非在块作用域)extern- 静态存储期与外部链接(除非已声明带内部链接)
  | 
(C11 起) | 
解释
存储类指定符出现于声明中。至多可使用一个指定符,除了能将 _Thread_local 与 static 或 extern 组合以调整链接 (C11 起)。存储类指定符确定其所声明的名称的二个独立属性:存储期与链接。
auto 指定符只对声明于块作用域的对象(除了函数参数列表)允许。它指示自动存储期与无链接,也是这种声明的默认属性。register 指定符只对声明于块作用域的对象允许,包括函数参数列表。它指示自动存储期与无链接(即这种声明的默认属性),但另外提示优化器,若可能则将此对象的值存储于 CPU 寄存器中。无论此优化是否发生,声明为 register 的对象不能用作取址运算符的参数,不能用 _Alignas (C11 起),而且 register 数组不能转换为指针。static 指定符指定静态存储期(除非与 _Thread_local 组合) (C11 起)和内部链接(除非用于块作用域)。它能用于在文件作用域的函数,以及文件和块作用域的对象,但不能用于函数参数列表。extern 指定静态存储期(除非与 _Thread_local 组合) (C11 起)和外部链接。它能用于文件和块作用域中的函数和对象声明(除了函数参数列表)。若 extern 出现在已经声明带内部链接的标识符的再声明上,则链接仍为内部。否则(若前一声明为外部、无链接或不在作用域内)链接为外部。| 
 5)  
_Thread_local 指示线程存储期。它不能用于函数声明。若将它用在对象声明上,则它必须在同一对象的每次声明上都存在。若将它用在块作用域声明上,则必须与 static 或 extern 之一组合以决定链接。 | 
(C11 起) | 
若不提供存储类指定符,则默认为:
-  对所有函数为 
extern -  对在文件作用域的对象为 
extern -  对在块作用域的对象为 
auto 
对于任何用存储类指定符声明的结构体或联合体,存储期(但非链接)递归地应用到其成员。
在块作用域的函数声明能使用 extern 或完全不使用存储类指定符。在文件作用域的函数声明能使用 extern 或 static 。
函数参数不能使用异于 register 的存储类指定符。注意 static 在数组类型的函数参数中有特殊含义。
存储期
每个对象都有称为存储期的属性,它限制对象的生存期。 C 中有四种存储期:
- 静态存储期。存储期是整个程序的执行过程,只在 
main函数之前初始化一次存储于对象的值。所有声明为static对象和所有带内部或外部链接且不声明为_Thread_local(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
注意
一般通过定义于头文件 threads.h 的便利宏 thread_local 使用关键词 _Thread_local 。
C 语言文法中, typedef 指定符在形式上列作存储类指定符,但它被用于声明类型名,而不指定存储。
在文件作用域的 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
引用
- C11 standard (ISO/IEC 9899:2011):
 
- 6.2.2 Linkages of identifiers (p: 36-37)
 
- 6.2.4 Storage durations of objects (p: 38-39)
 
- 6.7.1 Storage-class specifiers (p: 109-110)
 
- C99 standard (ISO/IEC 9899:1999):
 
- 6.2.2 Linkages of identifiers (p: 30-31)
 
- 6.2.4 Storage durations of objects (p: 32)
 
- 6.7.1 Storage-class specifiers (p: 98-99)
 
- C89/C90 standard (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