外部和暂定定义
在翻译单元的顶层(即经过预处理器处理后的源文件和所有 #include),每个 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 声明不同,暂定定义可能与同一标识符的另一个声明在链接上不一致。如果同一标识符的两个声明在作用域内并且具有不同的链接,则行为未定义
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 起)(C23 止)、alignof
(C23 起)或 typeof
(C23 起)之外的任何表达式中,则在该翻译单元中必须有且仅有一个该标识符的外部定义。
整个程序可以有零个或一个具有外部链接的每个标识符的外部定义。
如果具有外部链接的标识符用于除非变长数组 (VLA),(C99 起) sizeof
、_Alignof
(C11 起)(C23 止)、alignof
(C23 起)或 typeof
(C23 起)之外的任何表达式中,则在整个程序中必须有且仅有一个该标识符的外部定义。
[编辑] 注意
不同翻译单元中的内联定义不受单一定义规则的约束。有关内联函数定义的详细信息,请参阅 |
(C99 起) |
有关文件作用域声明中关键字 extern 的含义,请参阅存储期和链接
有关声明和定义之间的区别,请参阅定义。
暂定定义是为了标准化各种 C89 之前的前向声明具有内部链接的标识符的方法而发明的。
[编辑] 参考
- C23 标准 (ISO/IEC 9899:2024)
- 6.9 外部定义 (p: TBD)
- 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 外部定义