为什么 ld 链接器允许具有相同方法的多个类定义

Why does the ld linker allow multiple class definitions with the same methods?

本文关键字:方法 定义 链接 ld 许具 为什么      更新时间:2023-10-16

考虑这个文件,first.cpp,包含一个类定义和用途:

#include <iostream>
struct Foo
{
    Foo(){ std::cout << "Foo()" << std::endl; }
    ~Foo(){ std::cout << "~Foo()" << std::endl; }
};
int main(){
    Foo f;
    return 0;
}

另一个是second.cpp,包含冲突的类定义:

#include <iostream>
struct Foo
{
    Foo();
    ~Foo();
};
Foo::~Foo(){ std::cout << "wrong ~Foo()" << std::endl; }

当定义了两个具有相同名称的函数时,链接器会抱怨重复的符号,但这些具有重复类方法的文件编译时没有错误。

我用这些命令编译:

$ g++ -c second.cpp -o second
$ g++ second first.cpp -o first

将参数重新排序到第二个g++调用不会更改输出。

first运行时,这是输出:

$ ./first
Foo()
wrong ~Foo()

为什么链接器允许重复的类方法?如果显然是允许的,为什么要打印wrong ~Foo()

再次,未定义的行为。你的程序对Foo的析构函数有多个定义,这意味着它违反了ODR。程序是错误的,任何事情都可能发生。

为什么链接器不拾取它?在类定义中定义函数时,它会隐式inline。编译器通常将这些函数标记为"弱符号"。然后,链接器获取所有翻译单元并尝试解析符号。如果需要,链接器将删除弱符号(即,如果符号已在其他地方定义)。

截至程序的实际输出,看起来编译器实际上并没有内联对构造函数的调用,因此在运行时调度到链接器留下的符号(非弱符号)


为什么链接器允许有重复的方法?

因为所有(但最多一个)都是弱符号(即 inline

为什么在这种情况下,打印了错误的 ~Foo()?

因为调用未内联,并且链接器删除了弱符号