Я не хочу знать, включен ли RVO по умолчанию для C. Я знаю, что флаг "-fno-elide-constructors" не разрешен для g cc, но, возможно, у меня отсутствует эта функция.
По сути, я пытаюсь скомпилировать эти два кода:
// main.c :
typedef struct C {
int a;
int b;
int c;
} C;
C f() {
C a;
a.a = 333;
a.b = 444;
a.c = 555;
return a;
}
C g() { return f(); }
int main() {
C obj = g();
obj.a = 666;
obj.b = 777;
obj.c = 888;
}
И этот:
// main.cpp :
struct C {
C() {}
C(const C&) {}
int a;
int b;
int c;
};
C f() {
C a;
a.a = 333;
a.b = 444;
a.c = 555;
return a;
}
C g() { return f(); }
int main() {
C obj = g();
obj.a = 666;
obj.b = 777;
obj.c = 888;
}
Я компилирую оба кода одинаково:
g cc main. c -S -o c_main.s
g ++ main. cpp -S -o cpp_main.s
У меня есть такой asm:
.file "main.c"
.text
.globl f
.def f; .scl 2; .type 32; .endef
.seh_proc f
f:
pushq %rbp
.seh_pushreg %rbp
movq %rsp, %rbp
.seh_setframe %rbp, 0
subq $16, %rsp
.seh_stackalloc 16
.seh_endprologue
movq %rcx, 16(%rbp)
movl $333, -12(%rbp)
movl $444, -8(%rbp)
movl $555, -4(%rbp)
movq 16(%rbp), %rax
movq -12(%rbp), %rdx
movq %rdx, (%rax)
movl -4(%rbp), %edx
movl %edx, 8(%rax)
movq 16(%rbp), %rax
addq $16, %rsp
popq %rbp
ret
.seh_endproc
.globl g
.def g; .scl 2; .type 32; .endef
.seh_proc g
g:
pushq %rbp
.seh_pushreg %rbp
movq %rsp, %rbp
.seh_setframe %rbp, 0
subq $32, %rsp
.seh_stackalloc 32
.seh_endprologue
movq %rcx, 16(%rbp)
movq 16(%rbp), %rax
movq %rax, %rcx
call f
movq 16(%rbp), %rax
addq $32, %rsp
popq %rbp
ret
.seh_endproc
.def __main; .scl 2; .type 32; .endef
.globl main
.def main; .scl 2; .type 32; .endef
.seh_proc main
main:
pushq %rbp
.seh_pushreg %rbp
movq %rsp, %rbp
.seh_setframe %rbp, 0
subq $48, %rsp
.seh_stackalloc 48
.seh_endprologue
call __main
leaq -12(%rbp), %rax
movq %rax, %rcx
call g
movl $666, -12(%rbp)
movl $777, -8(%rbp)
movl $888, -4(%rbp)
movl $0, %eax
addq $48, %rsp
popq %rbp
ret
.seh_endproc
.ident "GCC: (x86_64-posix-seh-rev0, Built by MinGW-W64 project) 8.1.0"
А для cpp:
.file "main.cpp"
.text
.section .text$_ZN1CC1Ev,"x"
.linkonce discard
.align 2
.globl _ZN1CC1Ev
.def _ZN1CC1Ev; .scl 2; .type 32; .endef
.seh_proc _ZN1CC1Ev
_ZN1CC1Ev:
.LFB2:
pushq %rbp
.seh_pushreg %rbp
movq %rsp, %rbp
.seh_setframe %rbp, 0
.seh_endprologue
movq %rcx, 16(%rbp)
nop
popq %rbp
ret
.seh_endproc
.text
.globl _Z1fv
.def _Z1fv; .scl 2; .type 32; .endef
.seh_proc _Z1fv
_Z1fv:
.LFB6:
pushq %rbp
.seh_pushreg %rbp
movq %rsp, %rbp
.seh_setframe %rbp, 0
subq $32, %rsp
.seh_stackalloc 32
.seh_endprologue
movq %rcx, 16(%rbp)
movq 16(%rbp), %rcx
call _ZN1CC1Ev
movq 16(%rbp), %rax
movl $333, (%rax)
movq 16(%rbp), %rax
movl $444, 4(%rax)
movq 16(%rbp), %rax
movl $555, 8(%rax)
nop
movq 16(%rbp), %rax
addq $32, %rsp
popq %rbp
ret
.seh_endproc
.globl _Z1gv
.def _Z1gv; .scl 2; .type 32; .endef
.seh_proc _Z1gv
_Z1gv:
.LFB7:
pushq %rbp
.seh_pushreg %rbp
movq %rsp, %rbp
.seh_setframe %rbp, 0
subq $32, %rsp
.seh_stackalloc 32
.seh_endprologue
movq %rcx, 16(%rbp)
movq 16(%rbp), %rax
movq %rax, %rcx
call _Z1fv
movq 16(%rbp), %rax
addq $32, %rsp
popq %rbp
ret
.seh_endproc
.def __main; .scl 2; .type 32; .endef
.globl main
.def main; .scl 2; .type 32; .endef
.seh_proc main
main:
.LFB8:
pushq %rbp
.seh_pushreg %rbp
movq %rsp, %rbp
.seh_setframe %rbp, 0
subq $48, %rsp
.seh_stackalloc 48
.seh_endprologue
call __main
leaq -12(%rbp), %rax
movq %rax, %rcx
call _Z1gv
movl $666, -12(%rbp)
movl $777, -8(%rbp)
movl $888, -4(%rbp)
movl $0, %eax
addq $48, %rsp
popq %rbp
ret
.seh_endproc
.ident "GCC: (x86_64-posix-seh-rev0, Built by MinGW-W64 project) 8.1.0"
Для сборки cpp вы можете удалить служебную 20 первую строку, и у вас есть одинаковые номера строк для c asm и c ++ asm.
Я не очень хорошо разбираюсь в сборке код, но с этим результатом, я думаю, я могу сказать, что RVO включен для C.
Конечно, если я скомпилирую код C ++ с -fg cc no-elide-constructors, у меня так гораздо больше сборочной линии. Вот почему я думаю, что мой экземпляр структуры в функции 'f' не "копируется" в C и "конструируется" только один раз. В данной функции сборки мы ясно видим, что нет никаких манипуляций со структурой поля 'C'.
Я ошибаюсь?
Редактировать: компилировать с -O0 дают то же самое сборка для магистрали. c.