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 字节),作为实际的变量大小。 - 当某一个目标文件存在已初始化的变量,而其它目标文件存在该变量同名的尝试性变量,则链接程序会使用已初始化的变量的大小为该变量分配存储,并将所有相同名称的尝试性变量都链接到这个存储地址。
注意:如果尝试性变量的大小超过了已初始化的变量大小,程序中对尝试性变量的访问肯定会越界。 - 当多个目标文件存在同名的已初始化的变量,则链接程序报错。
|