Namespaces
Variants

External and tentative definitions

From cppreference.net

翻译单元 的最高层级(即经过预处理器处理包含所有#include指令后的源文件),每个C程序都是由一系列 声明 组成的序列,这些声明通过 外部或内部链接 来声明函数和对象。这些声明被称为 外部声明 ,因为它们出现在任何函数的外部。

extern int n; // 具有外部链接的外部声明
int b = 1;    // 具有外部链接的外部定义
static const char *c = "abc"; // 具有内部链接的外部定义
int f(void)    // 具有外部链接的外部定义
{
    int a = 1; // 非外部
    return b;
}
static void x(void) // 具有内部链接的外部定义
{
}

使用外部声明定义的对象具有静态 存储期 ,因此不能使用 auto register 说明符 ,但 auto 可用于类型推断的情况除外 (C23 起) 。通过外部声明引入的标识符具有 文件作用域

目录

暂定定义

一个 试探性定义 是指没有初始化器的外部声明,且要么不带 存储类说明符 ,要么带有说明符 static

一个 试探性定义 是可能作为定义也可能不作为定义的声明。如果在同一翻译单元中较早或较晚找到了实际的外部定义,那么该试探性定义仅作为声明生效。

int i1 = 1;     // 定义,外部链接
int i1;         // 试探性定义,因 i1 已定义而作为声明
extern int i1;  // 声明,指向先前的定义
extern int i2 = 3; // 定义,外部链接
int i2;            // 试探性定义,因 i2 已定义而作为声明
extern int i2;     // 声明,指向外部链接定义

如果在同一翻译单元中没有其他定义,则试探性定义将作为实际定义,该定义会 空初始化 该对象。

int i3;        // 暂定性定义,外部链接
int i3;        // 暂定性定义,外部链接
extern int i3; // 声明,外部链接
// 在此翻译单元中,i3 被定义为如同通过 "int i3 = 0;" 定义

extern 声明(若先前声明已确立标识符的链接则不会改变其链接属性)不同,试探性定义可能与同一标识符的其他声明在链接属性上存在冲突。若同一标识符的两个声明同时处于作用域内且具有不同链接属性,则行为未定义:

static int i4 = 2; // 定义,内部链接
int i4;            // 未定义行为:与前一行的链接方式冲突
extern int i4;     // 声明,指向内部链接定义
static int i5; // 暂定定义,内部链接
int i5;        // 未定义行为:与前一行的链接方式冲突
extern int i5; // 指向先前的内部链接定义

具有内部链接的试探性定义必须具有完整类型。

static int i[]; // 错误,静态暂定定义中使用了不完整类型
int i[]; // 正确,等同于 int i[1] = {0};除非在同一文件中后续重新声明

单一定义规则

每个翻译单元对于每个具有 内部链接 的标识符( static 全局变量)可以拥有零个或一个外部定义。

若具有内部链接的标识符被用于除 非可变长度数组 (C99起) sizeof _Alignof (C11起) (C23前) alignof (C23起) typeof (C23起) 之外的任何表达式,则在该翻译单元中必须存在且仅存在一个该标识符的外部定义。

整个程序中,每个具有 外部链接 的标识符最多只能有一个外部定义。

若具有外部链接的标识符被用于任何表达式(除了 非可变长度数组、 (C99起) sizeof _Alignof (C11起) (C23前) alignof (C23起) typeof (C23起) 之外),则在整个程序中必须存在且仅存在一个该标识符的外部定义。

注释

不同翻译单元中的内联定义不受单一定义规则约束。有关内联函数定义的详细信息,请参阅 inline

(C99 起)

请参阅 存储期与链接 了解关键字 extern 在文件作用域声明中的含义

请参阅 定义 了解声明与定义之间的区别。

试探性定义是为了标准化C89之前各种处理内部链接标识符前向声明的方法而提出的概念。

参考文献

  • C23 标准 (ISO/IEC 9899:2024):
  • 6.9 外部定义 (页: 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 外部定义(页码:140-144)
  • C89/C90 标准 (ISO/IEC 9899:1990):
  • 3.7 外部定义