我试图想出一个我前一段时间的问题的答案(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
以不同的顺序出现。在这种情况下,它是无害的,但显然使等价检测更难。差异的解释是什么?
答案 0 :(得分:0)
你的问题让我很好奇所以我必须亲自看看。您可以查看here for version 1和here 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