6.9.3 外部对象定义
语义
- 如果某个对象标识符的声明具有文件作用域,并且带有初始化器,或者具有文件作用域并带有存储类说明符
thread_local,那么该声明就是该标识符的外部定义。 - 如果某个对象标识符的声明具有文件作用域、没有初始化器,并且也没有存储类说明符
extern或thread_local,那么该声明构成一个暂定定义。 - 如果一个翻译单元对某个标识符包含一个或多个暂定定义,并且没有该标识符的外部定义,那么其行为就如同该翻译单元在文件作用域上包含了一个对该标识符的带空初始化器声明,并按以下规则确定其类型:
- 如果到翻译单元结尾时,其复合类型是未知大小数组,那么把它视为元素类型取该复合元素类型、长度为
1的数组; - 否则,类型就是翻译单元结尾时得到的复合类型。
- 如果某个对象标识符的声明是暂定定义,并且具有内部链接,那么其声明类型不得是不完整类型。
示例
示例 1
c
int i1 = 1; // 定义,外部链接
static int i2 = 2; // 定义,内部链接
extern int i3 = 3; // 定义,外部链接
int i4; // 暂定定义,外部链接
static int i5; // 暂定定义,内部链接
int i1; // 有效的暂定定义,指向前一声明
int i2; // 依 6.2.2 属于未定义行为:链接属性不一致
int i3; // 有效的暂定定义,指向前一声明
int i4; // 有效的暂定定义,指向前一声明
int i5; // 依 6.2.2 属于未定义行为:链接属性不一致
extern int i1; // 指向前一声明,其链接为外部链接
extern int i2; // 指向前一声明,其链接为内部链接
extern int i3; // 指向前一声明,其链接为外部链接
extern int i4; // 指向前一声明,其链接为外部链接
extern int i5; // 指向前一声明,其链接为内部链接1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
示例 2
如果一个翻译单元包含:
c
int i[];1
并且到翻译单元结尾时,数组 i 仍然是不完整类型,那么隐式初始化器会使它成为一个只含一个元素的数组,并在程序启动时把该元素初始化为零。