外部和暂定定义
在 翻译单元 (即带有所有 #includes 的源文件,在预处理器之后)的顶层,每个 C 程序都是一系列 声明,这些声明使用 外部或内部链接 声明函数和对象。这些声明被称为 外部声明,因为它们出现在任何函数之外。
extern int n; // external declaration with external linkage int b = 1; // external definition with external linkage static const char *c = "abc"; // external definition with internal linkage int f(void) { // external definition with external linkage int a = 1; // non-external return b; } static void x(void) { // external definition with internal linkage }
使用外部声明声明的对象具有静态 存储期,因此不能使用 auto
或 register
说明符 除了 auto
可用于类型推断(自 C23 起)。外部声明引入的标识符具有 文件作用域。
内容 |
[编辑] 暂定定义
暂定定义 是一个外部声明,没有初始化器,并且没有 存储类说明符 或带有说明符 static
。
暂定定义 是一个可能也可能不作为定义的声明。如果在同一个翻译单元中找到实际的外部定义,则暂定定义仅充当声明。
int i1 = 1; // definition, external linkage int i1; // tentative definition, acts as declaration because i1 is defined extern int i1; // declaration, refers to the earlier definition extern int i2 = 3; // definition, external linkage int i2; // tentative definition, acts as declaration because i2 is defined extern int i2; // declaration, refers to the external linkage definition
如果没有相同翻译单元中的定义,则暂定定义充当实际定义,该定义 为空初始化 对象。
int i3; // tentative definition, external linkage int i3; // tentative definition, external linkage extern int i3; // declaration, external linkage // in this translation unit, i3 is defined as if by "int i3 = 0;"
与 extern 声明不同,如果以前的声明建立了链接,则 extern 声明不会更改标识符的链接,暂定定义可能在链接方面与相同标识符的另一个声明不一致。如果两个针对相同标识符的声明在作用域内并且具有不同的链接,则行为是未定义的。
static int i4 = 2; // definition, internal linkage int i4; // Undefined behavior: linkage disagreement with previous line extern int i4; // declaration, refers to the internal linkage definition static int i5; // tentative definition, internal linkage int i5; // Undefined behavior: linkage disagreement with previous line extern int i5; // refers to previous, whose linkage is internal
具有内部链接的暂定定义必须具有完整类型。
static int i[]; // Error, incomplete type in a static tentative definition int i[]; // OK, equivalent to int i[1] = {0}; unless redeclared later in this file
[编辑] 单定义规则
每个翻译单元可以为具有 内部链接 (static
全局)的每个标识符提供零个或一个外部定义。
如果具有内部链接的标识符用在除 非 VLA,(自 C99 起) sizeof
,_Alignof
(自 C11 起),或 typeof
(自 C23 起) 之外的任何表达式中,则该翻译单元中必须有一个且仅有一个外部定义。
整个程序可以为具有 外部链接 的每个标识符提供零个或一个外部定义。
如果具有外部链接的标识符用在除 非 VLA,(自 C99 起) sizeof
,_Alignof
(自 C11 起),或 typeof
(自 C23 起) 之外的任何表达式中,则整个程序中必须有一个且仅有一个外部定义。
[编辑] 注释
不同翻译单元中的内联定义不受单定义规则约束。有关内联函数定义的详细信息,请参阅 |
(自 C99 起) |
有关在文件范围内的声明中使用关键字 extern
的含义,请参阅 存储期和链接。
有关声明和定义之间的区别,请参阅 定义。
暂定定义是为了标准化 C89 之前各种用于前向声明具有内部链接的标识符的方法而发明的。
[编辑] 参考资料
- C17 标准 (ISO/IEC 9899:2018)
- 6.9 外部定义 (p: 113-116)
- C11 标准 (ISO/IEC 9899:2011)
- 6.9 外部定义 (p: 155-159)
- C99 标准 (ISO/IEC 9899:1999)
- 6.9 外部定义 (p: 140-144)
- C89/C90 标准 (ISO/IEC 9899:1990)
- 3.7 外部定义