我有两个 .c 文件:A1.c 和 A2.c
A1.c 如下:
int i=0;
void main()
{}
A2.c 如下:
int i=0;
void func()
{}
它编译得很好,但是当我尝试链接这两个 .o 文件时,出现“i 的多重定义”错误。我知道i
这里是一个全局变量,但它不需要extern
在其他文件中使用的关键字。在我的项目中,我没有使用extern
. 那我怎么会出错呢?
我有两个 .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:给定多个弱符号,选择任何一个弱符号。
您的代码 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/
Long story short, a statement like
extern int i;
is a declaration, while the statement
int i=0;
is a definition.
In C you can declare a variable many times in a program, but you can define it only once.The first statement signifies to A2 that the definition of the variable i is in another file.For one I can't understand why you are so apprehensive about using "extern".
在 C 中,可以从另一个编译单元访问全局变量,只要另一个编译单元通过声明它看到它存在extern
。链接器使工作具有链接外部声明和另一个.c 中的定义。
如果您希望它仅对您正在编译的 .c 可见,则必须将其指定为static
static int i = 0;
当然,它在链接上失败了:它试图组合两个引用两个不同内存位置的对象的对象文件。
在这种情况下,变量的真正定义在所有源代码中必须是唯一的,并且对这个变量的所有其他引用必须通过使用external
关键字来完成(as you sat)。
编译不会抱怨,因为它不知道您的两个文件的关系,只有链接器必须弄清楚这一点。