C 语言标准中有个术语叫 tentative definition,中文翻译为“尝试性定义”,一般具有外部连接属性的未初始化全局变量,都是尝试性定义。
例如:
- int a; // 是尝试性定义
- char b[20]; // 是尝试性定义
- int c = 0; // 已初始化,不是尝试性定义
- static int d; // 只有本文件作用域,不具有外部连接属性,不是尝试性定义
- void foo(void)
- {
- int e; // 局部变量,不是尝试性定义
- static int f; // 静态局部变量,不具有外部连接属性,不是尝试性定义
- ...
- }
关于目标文件中变量的链接情况,分为以下三种:
- 当多个目标文件存在相同名称的尝试性变量,链接程序会从中选择一个最大的 size,以这个 size 为该变量分配存储,并将所有相同名称的尝试性变量都链接到这个存储地址。
注:编译后的目标文件中是没有变量的类型信息的。
例如:- // file1.c
- int a; // 尝试性定义变量
- void foo(void)
- {
- a = 0x34333231;
- }
- // file2.c
- #include <stdio.h>
- char a[5]; // 尝试性定义变量
- void foo(void);
- int main(void)
- {
- foo();
- a[4] = '\0';
- printf("%s\n", a);
- }
在该例中,两个 C 文件都定义了名称为 a 的变量,大小和类型都不同,编译后,类型信息丢失,目标文件中只有变量的名称和大小信息,链接程序会选择较大的大小(file2.c 中定义的 5 字节),作为实际的变量大小。- 当某一个目标文件存在已初始化的变量,而其它目标文件存在该变量同名的尝试性变量,则链接程序会使用已初始化的变量的大小为该变量分配存储,并将所有相同名称的尝试性变量都链接到这个存储地址。
注意:如果尝试性变量的大小超过了已初始化的变量大小,程序中对尝试性变量的访问肯定会越界。 - 当多个目标文件存在同名的已初始化的变量,则链接程序报错。
|