c ++代码
#include <cstdio>
#include <cstdlib>
struct trivialStruct
{
trivialStruct();
~trivialStruct();
int *a;
float *b;
float *c;
};
trivialStruct::trivialStruct() : a((int*)malloc(sizeof(int))), b((float*)malloc(sizeof(float))), c((float*)malloc(sizeof(float)))
{
*a = 100;
*b = 200;
*c = 300;
}
trivialStruct::~trivialStruct()
{
free(a);
free(b);
free(c);
a = nullptr;
b = nullptr;
c = nullptr;
}
int main()
{
trivialStruct A;
printf("%d, %f, %f", *A.a, *A.b, *A.c);
return 0;
}
组件
.section __TEXT,__text,regular,pure_instructions
.globl __ZN13trivialStructC1Ev
.align 4, 0x90
__ZN13trivialStructC1Ev: ## @_ZN13trivialStructC1Ev
.cfi_startproc
## BB#0: ## %entry
push RBP
Ltmp3:
.cfi_def_cfa_offset 16
Ltmp4:
.cfi_offset rbp, -16
mov RBP, RSP
Ltmp5:
.cfi_def_cfa_register rbp
push R15
push R14
push RBX
push RAX
Ltmp6:
.cfi_offset rbx, -40
Ltmp7:
.cfi_offset r14, -32
Ltmp8:
.cfi_offset r15, -24
mov RBX, RDI
mov EDI, 4
call _malloc
mov R14, RAX
mov QWORD PTR [RBX], R14
mov EDI, 4
call _malloc
mov R15, RAX
mov QWORD PTR [RBX + 8], R15
mov EDI, 4
call _malloc
mov QWORD PTR [RBX + 16], RAX
mov DWORD PTR [R14], 100
mov DWORD PTR [R15], 1128792064
mov DWORD PTR [RAX], 1133903872
add RSP, 8
pop RBX
pop R14
pop R15
pop RBP
ret
.cfi_endproc
.globl __ZN13trivialStructC2Ev
.align 4, 0x90
__ZN13trivialStructC2Ev: ## @_ZN13trivialStructC2Ev
.cfi_startproc
## BB#0: ## %entry
push RBP
Ltmp12:
.cfi_def_cfa_offset 16
Ltmp13:
.cfi_offset rbp, -16
mov RBP, RSP
Ltmp14:
.cfi_def_cfa_register rbp
push R15
push R14
push RBX
push RAX
Ltmp15:
.cfi_offset rbx, -40
Ltmp16:
.cfi_offset r14, -32
Ltmp17:
.cfi_offset r15, -24
mov RBX, RDI
mov EDI, 4
call _malloc
mov R14, RAX
mov QWORD PTR [RBX], R14
mov EDI, 4
call _malloc
mov R15, RAX
mov QWORD PTR [RBX + 8], R15
mov EDI, 4
call _malloc
mov QWORD PTR [RBX + 16], RAX
mov DWORD PTR [R14], 100
mov DWORD PTR [R15], 1128792064
mov DWORD PTR [RAX], 1133903872
add RSP, 8
pop RBX
pop R14
pop R15
pop RBP
ret
.cfi_endproc
.globl __ZN13trivialStructD1Ev
.align 4, 0x90
__ZN13trivialStructD1Ev: ## @_ZN13trivialStructD1Ev
.cfi_startproc
## BB#0: ## %entry
push RBP
Ltmp21:
.cfi_def_cfa_offset 16
Ltmp22:
.cfi_offset rbp, -16
mov RBP, RSP
Ltmp23:
.cfi_def_cfa_register rbp
push RBX
push RAX
Ltmp24:
.cfi_offset rbx, -24
mov RBX, RDI
mov RDI, QWORD PTR [RBX]
call _free
mov RDI, QWORD PTR [RBX + 8]
call _free
mov RDI, QWORD PTR [RBX + 16]
call _free
mov QWORD PTR [RBX + 16], 0
mov QWORD PTR [RBX + 8], 0
mov QWORD PTR [RBX], 0
add RSP, 8
pop RBX
pop RBP
ret
.cfi_endproc
.globl __ZN13trivialStructD2Ev
.align 4, 0x90
__ZN13trivialStructD2Ev: ## @_ZN13trivialStructD2Ev
.cfi_startproc
## BB#0: ## %entry
push RBP
Ltmp28:
.cfi_def_cfa_offset 16
Ltmp29:
.cfi_offset rbp, -16
mov RBP, RSP
Ltmp30:
.cfi_def_cfa_register rbp
push RBX
push RAX
Ltmp31:
.cfi_offset rbx, -24
mov RBX, RDI
mov RDI, QWORD PTR [RBX]
call _free
mov RDI, QWORD PTR [RBX + 8]
call _free
mov RDI, QWORD PTR [RBX + 16]
call _free
mov QWORD PTR [RBX + 16], 0
mov QWORD PTR [RBX + 8], 0
mov QWORD PTR [RBX], 0
add RSP, 8
pop RBX
pop RBP
ret
.cfi_endproc
.section __TEXT,__literal8,8byte_literals
.align 3
LCPI4_0:
.quad 4641240890982006784 ## double 200
LCPI4_1:
.quad 4643985272004935680 ## double 300
.section __TEXT,__text,regular,pure_instructions
.globl _main
.align 4, 0x90
_main: ## @main
.cfi_startproc
## BB#0: ## %entry
push RBP
Ltmp34:
.cfi_def_cfa_offset 16
Ltmp35:
.cfi_offset rbp, -16
mov RBP, RSP
Ltmp36:
.cfi_def_cfa_register rbp
lea RDI, QWORD PTR [RIP + L_.str]
movsd XMM0, QWORD PTR [RIP + LCPI4_0]
movsd XMM1, QWORD PTR [RIP + LCPI4_1]
mov ESI, 100
mov AL, 2
call _printf
xor EAX, EAX
pop RBP
ret
.cfi_endproc
.section __TEXT,__cstring,cstring_literals
L_.str: ## @.str
.asciz "%d, %f, %f"
.subsections_via_symbols
命令 clang ++ -S -O2 -std = c ++ 11 -mllvm --x86-asm-syntax = intel -fno-exceptions main.cpp
如您所见,代码的两部分是相同的(构造函数和析构函数)
我不知道为什么编译器生成两部分代码而不只是一部分? 我不熟悉汇编,但看起来这只是使代码成为 更胖(也许更慢)。
答案 0 :(得分:3)
这是您平台的ABI的一部分,并且不符合标准。构造函数和析构函数都可以在二进制文件中生成多个符号。例如,Itanium C ++ ABI将生成最多3个构造函数/析构函数:
不同的符号承担略有不同的职责,因为实现可能需要根据对象的创建/销毁方式做不同的事情。在您的特定情况下,代码很简单,所有构造函数可能生成完全相同的代码,但它们需要符合ABI,ABI使它们能够实现更复杂的用例。
例如,完整的对象构造函数将初始化虚拟基础,而基础对象构造函数将跳过此部分构造。如果存在多个/虚拟继承和虚函数,则完整对象中的vptr可能必须跳过不同的中间表集,具体取决于该子对象的实例化方式。
如果您想要除 ABI强制要求以外的解释,您应该查看特定ABI的文档。您还可以查看 Inside C ++对象模型,即使是旧的,也包含对要解决的问题的详细描述以及提供的一些解决方案。