代码之家  ›  专栏  ›  技术社区  ›  Daniel Langr

GCC不为类外默认复制构造函数生成机器代码

  •  0
  • Daniel Langr  · 技术社区  · 7 月前

    假设以下源文件(翻译单位;TU):

    struct X {
        int i;
        
        X(const X&);
        X(X&&);
    };
    
    X::X(const X&) = default;
    X::X(X&&) = default
    

    如果我用Clang编译它,它会为复制和移动构造函数生成机器代码。但是,GCC仅为移动构造函数生成它,并且在生成的对象文件中缺少复制构造函数的机器代码。我起初以为这是与编译器资源管理器有关的问题,但后来我在本地Linux系统上使用 objdump .

    现场演示: https://godbolt.org/z/1re4brr6P

    我不明白这一点,因为一旦我有另一个带有复制构造函数调用的TU,就需要从机器代码中调用它: https://godbolt.org/z/3YaMTd5do 。因此,GCC在第二个TU中生成复制构造函数的调用,但在第一个TU不生成其机器代码。那么链接器如何将目标文件链接在一起呢?

    1 回复  |  直到 7 月前
        1
  •  4
  •   user17732522    7 月前

    这只是编译器资源管理器如何呈现输出的问题(就像 objdump ):

    GCC在同一地址为两个构造函数定义了符号,因为函数具有完全相同的行为。符号表:

    $ nm test.o 
    0000000000000000 T _ZN1XC1EOS_
    0000000000000000 T _ZN1XC1ERKS_
    0000000000000000 T _ZN1XC2EOS_
    0000000000000000 T _ZN1XC2ERKS_
    
    $ nm -C test.o
    0000000000000000 T X::X(X&&)
    0000000000000000 T X::X(X const&)
    0000000000000000 T X::X(X&&)
    0000000000000000 T X::X(X const&)
    

    通常,编译器无法优化两个函数以使其具有完全相同的地址,而是将其中一个相同的函数编译为一个跳转指令到另一个,但对于构造函数(和其他非静态(隐式对象)成员函数)来说,这是可以的,因为在C++中无法观察构造函数的地址。

    在编译器资源管理器中,如果您查看的是汇编级别而不是反汇编的二进制文件,您还可以通过编译器窗口左侧的第三个图标禁用汇编指令的过滤。然后,您将看到导致所有这些符号在同一位置定义的指令。不幸的是,会有很多指令,所以读起来有点困难。在“编译为二进制对象”/“链接到二进制”模式下,这是不可能的。

    推荐文章