【问题标题】:Linker doesn't notify multiple definitions链接器不通知多个定义
【发布时间】:2018-03-23 17:35:13
【问题描述】:

我有两个文件 foo.cfoo2.c 完全相同。如果我链接到它们两个,那么链接器将抛出一个错误,抱怨多个函数定义。

但是如果我首先将一个文件编译成静态库并链接到另一个目标文件和库,那么链接过程会正常完成。我在 Ubuntu 16.04 上使用 gcc 5.4.0。

foo.cfoo2.c

#include <stdio.h>

void fooxyz(void) {
    printf("foo\n");
}

ma​​in.c:

#include <stdio.h>

void fooxyz(void);

int main(void) {
    fooxyz();
    return 1;
}

现在将 foo2 编译并归档到 libfoo2.a 中:

$ gcc -c main.c foo.c foo2.c
$ ar rcs libfoo2.a foo2.o
$ gcc -o main main.o foo.o -L. -lfoo2
$ ./main
foo

为什么链接器不会抛出关于函数fooxyz的多重定义的错误,因为它是在两个地方定义的?谢谢。

【问题讨论】:

    标签: c gcc linker


    【解决方案1】:

    但是如果我首先将一个文件编译成静态库并链接到另一个目标文件和库,那么链接过程就会正常完成。我在 Ubuntu 16.04 上使用 gcc 5.4.0。

    这是意料之中的。

    只有当它没有在任何被链接的目标文件中定义时,才使用库中的符号。

    【讨论】:

    • 所以我想这就是库被放在链接器命令中的目标文件后面的原因。
    • @radiohead:是的;这就是库应该在命令行上跟随目标文件的原因之一。你可以试验两个不同版本的fooxyz()——比如使用printf("%s:%s()\n", __FILE__, __func__);来打印文件名。然后查看链接了哪个函数。尝试改变库,以不同的顺序替换目标文件,看看你得到了什么。但是,结果是不确定的。也就是说,没有规范说明单个库中相同函数名的两个实现中的哪一个实际上会被选中。所以,双重定义是个问题!
    • @radiohead,您可以在链接器命令中的目标文件之前使用库。行为将完全相同。这只是一个好习惯。
    • @RSahu:这取决于系统和库的类型。对于静态库,如果对函数的第一次引用位于定义它的库之后列出的目标文件中,则大多数链接器不会重新扫描库。在目标文件之后列出库更好。您必须非常自信,您知道自己在做什么才能做到这一点。可以在一个系统上运行的东西不一定适用于其他系统。
    • @JonathanLeffler 同意。刚试过gcc -o main main.o -L. -lfoo2 foo.o,这次链接器抛出了多个定义错误。我在此页面中找到了一些有用的信息来解释这种行为:eli.thegreenplace.net/2013/07/09/…
    猜你喜欢
    • 2018-05-05
    • 1970-01-01
    • 1970-01-01
    • 2012-12-09
    • 2015-08-24
    • 2013-07-19
    • 1970-01-01
    相关资源
    最近更新 更多