5

我有两个 .c 文件:A1.c 和 A2.c

A1.c 如下:

int i=0;
void main()
{}

A2.c 如下:

int i=0;
void func()
{}

它编译得很好,但是当我尝试链接这两个 .o 文件时,出现“i 的多重定义”错误。我知道i这里是一个全局变量,但它不需要extern在其他文件中使用的关键字。在我的项目中,我没有使用extern. 那我怎么会出错呢?

4

4 回答 4

7

在编译时,编译器将每个全局符号作为强符号或弱符号导出到汇编器,汇编器将此信息隐式编码到可重定位目标文件的符号表中。函数和初始化的全局变量得到强符号。未初始化的全局变量获得弱符号。

鉴于这种强符号和弱符号的概念,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/

于 2015-01-05T22:50:27.173 回答
5

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".

于 2013-04-16T14:16:08.313 回答
3

在 C 中,可以从另一个编译单元访问全局变量,只要另一个编译单元通过声明它看到它存在extern。链接器使工作具有链接外部声明和另一个.c 中的定义。

如果您希望它仅对您正在编译的 .c 可见,则必须将其指定为static

static int i = 0;
于 2013-04-16T13:56:58.953 回答
-1

当然,它在链接上失败了:它试图组合两个引用两个不同内存位置的对象的对象文件。

在这种情况下,变量的真正定义在所有源代码中必须是唯一的,并且对这个变量的所有其他引用必须通过使用external关键字来完成(as you sat)。

编译不会抱怨,因为它不知道您的两个文件的关系,只有链接器必须弄清楚这一点。

于 2013-04-16T13:57:18.577 回答