为什么我的手写复制构造函数生成的代码与默认代码不同?

时间:2017-03-06 18:05:16

标签: c++ g++

我试图想出一个我前一段时间的问题的答案(Automatically determine if user-defined function is equivalent to the implicit one)。我的想法是我会编译进出复制构造函数,然后反汇编代码,并检查它们是否相同。代码:

struct A
{
    int B;
    A() : B(0) { }
#ifdef COPY_CONSTRUCTOR
    A(const A& a) : B(a.B) { }
#endif
};

#include <stdio.h>
int main()
{
    A a;
    A b(a);
    printf("%d", b.B);
}

编译(cygwin gcc v4.9.3):

gcc -o a1.exe main.cpp -std=c++11 -g -O0 -DCOPY_CONSTRUCTOR
gcc -o a2.exe main.cpp -std=c++11 -g -O0 -fno-elide-constructors

然后转储反汇编的副本构造函数(_ZN1AC1ERKS_是A复制构造函数的错位名称):

gdb -batch -ex 'file a1.exe' -ex 'disass _ZN1AC1ERKS_'

产地:

Dump of assembler code for function A::A(A const&):
   0x0000000100401770 <+0>:     push   %rbp
   0x0000000100401771 <+1>:     mov    %rsp,%rbp
   0x0000000100401774 <+4>:     mov    %rcx,0x10(%rbp)
   0x0000000100401778 <+8>:     mov    %rdx,0x18(%rbp)
   0x000000010040177c <+12>:    mov    0x18(%rbp),%rax
   0x0000000100401780 <+16>:    mov    (%rax),%edx
   0x0000000100401782 <+18>:    mov    0x10(%rbp),%rax
   0x0000000100401786 <+22>:    mov    %edx,(%rax)
   0x0000000100401788 <+24>:    pop    %rbp
   0x0000000100401789 <+25>:    retq
End of assembler dump.

gdb -batch -ex 'file a2.exe' -ex 'disass _ZN1AC1ERKS_'

产地:

Dump of assembler code for function A::A(A const&):
   0x0000000100401770 <+0>:     push   %rbp
   0x0000000100401771 <+1>:     mov    %rsp,%rbp
   0x0000000100401774 <+4>:     mov    %rcx,0x10(%rbp)
   0x0000000100401778 <+8>:     mov    %rdx,0x18(%rbp)
   0x000000010040177c <+12>:    mov    0x10(%rbp),%rax
   0x0000000100401780 <+16>:    mov    0x18(%rbp),%rdx
   0x0000000100401784 <+20>:    mov    (%rdx),%edx
   0x0000000100401786 <+22>:    mov    %edx,(%rax)
   0x0000000100401788 <+24>:    pop    %rbp
   0x0000000100401789 <+25>:    retq
End of assembler dump.

它们是相同的,除了行mov 0x10(%rbp),%rax以不同的顺序出现。在这种情况下,它是无害的,但显然使等价检测更难。差异的解释是什么?

1 个答案:

答案 0 :(得分:0)

你的问题让我很好奇所以我必须亲自看看。您可以查看here for version 1here for version 2,看看结果是否真的相同。

两种变体都被优化了!

这是反汇编:

.LC0:
        .string "%d"
Test():
        push    0
        push    OFFSET FLAT:.LC0
        call    printf
        pop     eax
        pop     edx
        push    0
        push    OFFSET FLAT:.LC0
        call    printf
        pop     ecx
        pop     eax
        ret

要了解非优化版本的不同之处,您可能需要检查gcc的来源。

Visual Studio也提供相同的结果:

int main()
{
    A a;
    A b(a);
    printf("%d", b.B);
00B41000  push        0  
00B41002  push        0B499A0h  
00B41007  call        printf (0B4102Dh)  
    printf("%d", a.B);
00B4100C  push        0  
00B4100E  push        0B499A4h  
00B41013  call        printf (0B4102Dh)  
00B41018  add         esp,10h  
    return 0;
0127101B  xor         eax,eax  
}
0127101D  ret