我有两个。c文件:A1.c和A2.c
A1.c如下:
int i=0;
void main()
{}
A2.c如下:
int i=0;
void func()
{}
它编译得很好,但当我试图链接这两个。o文件时,有一个"I的多个定义"错误。我理解i
在这里是一个全局变量,但它不需要在其他文件中使用extern
关键字吗?在我的项目中,我没有使用extern
。为什么会出现错误呢?
在编译时,编译器将每个全局符号导出为强符号或弱符号,汇编器将这些信息隐式地编码在可重定位对象文件的符号表中。函数和初始化的全局变量获得强符号。未初始化的全局变量得到弱符号。
考虑到强弱符号的概念,Unix连接器使用以下规则来处理多重定义的符号:
规则1:不允许使用多个强符号。
规则2:给定一个强符号和多个弱符号,选择强符号。
规则3:给定多个弱符号,选择其中任意一个
代码,
int i=0; // Strong Symbol
void main() {}
A2.c如下:
int i=0; // Strong symbol
void func() {}
根据规则1这是不允许的。
查看更多详细信息:http://www.geeksforgeeks.org/how-linkers-resolve-multiply-defined-global-symbols/
长话短说,像
extern int i;
是一个声明,而语句
int i=0;
是定义。
在C语言中,你可以在一个程序中多次声明一个变量,但是你只能定义它一次。第一个语句向A2表示变量i的定义在另一个文件中。首先,我不明白你为什么对使用"extern"这么担心。
在C中,只要另一个编译单元看到全局变量存在,就可以从另一个编译单元访问全局变量,通过将其声明为extern
。链接器使作业将外部声明和另一个。c中的定义链接起来。
如果你希望它只对你正在编译的。c可见,你必须指定它为static
static int i = 0;
当然,它在链接上失败了:它试图组合两个对象文件,这两个文件在两个不同的内存位置引用一个对象。
在这种情况下,变量的真正定义在所有源代码中必须是唯一的,并且对该变量的所有其他引用必须通过使用external
关键字(如您所见)来完成。
编译器不会报错,因为它不知道你的两个文件的关系,只有链接器需要弄清楚。