我有两个.c文件:A1.c和A2.c
A1.c如下:
int i=0;
void main()
{}
A2.c如下:
int i=0;
void func()
{}
它编译得很好但是当我尝试链接这两个.o文件时,会出现“i的多重定义”错误。
我理解i
这里是一个全局变量,但是不需要在其他文件中使用extern
关键字。在我的项目中,我没有使用extern
。那怎么会出错呢?
答案 0 :(得分:5)
长话短说,像
这样的陈述extern int i;
是声明,而声明是
int i=0;
是定义。
在C中你可以在一个程序中多次声明一个变量,但你只能定义一次。第一个语句向A2表示变量i的定义在另一个文件中。对于一个我无法理解为什么你对使用“extern”非常担心。
答案 1 :(得分:5)
在编译时,编译器将每个全局符号作为强或弱导出到汇编程序,并且汇编程序隐式地在可重定位目标文件的符号表中对此信息进行编码。函数和初始化的全局变量获得强符号。未初始化的全局变量得到弱符号。
鉴于强弱符号的这一概念,Unix链接器使用以下规则来处理多重定义的符号:
规则1:不允许使用多个强符号 规则2:如果是强符号和多个弱符号,请选择强符号 规则3:给定多个弱符号,选择任何弱符号。
你的代码, A1.c如下:
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/
答案 2 :(得分:3)
在C中,只要该另一个编译单元看到它存在,就可以从另一个编译单元访问全局变量,方法是声明它extern
。链接器使作业在另一个.c。
如果您希望它仅对您正在编译的.c可见,则必须将其指定为static
static int i = 0;
答案 3 :(得分:-1)
当然它在链接上失败了:它尝试组合两个引用两个不同内存位置对象的目标文件。
在这种情况下,变量的实际定义必须在所有源代码中都是唯一的,并且所有其他对此变量的引用必须通过使用external
关键字(如您所见)来完成。 / p>
编译没有抱怨,因为它不知道你的两个文件的关系,只有链接器必须弄明白。