1.基本类型的返回值
int add(int a, int b) { int c = 0; b = c++; return a+b; } int init() { int a = add(3, 4); return a; }
对应的汇编如下:
.file "list initialization.cpp" .text .globl _Z3addii .type _Z3addii, @function _Z3addii: .LFB0: .cfi_startproc pushl %ebp .cfi_def_cfa_offset 8 .cfi_offset 5, -8 movl %esp, %ebp .cfi_def_cfa_register 5 subl $16, %esp movl $0, -8(%ebp) movl -8(%ebp), %eax movl %eax, -4(%ebp) addl $1, -8(%ebp) movl -4(%ebp), %eax movl 8(%ebp), %edx addl %edx, %eax leave .cfi_restore 5 .cfi_def_cfa 4, 4 ret .cfi_endproc .LFE0: .size _Z3addii, .-_Z3addii .globl _Z4initv .type _Z4initv, @function _Z4initv: .LFB1: .cfi_startproc pushl %ebp .cfi_def_cfa_offset 8 .cfi_offset 5, -8 movl %esp, %ebp .cfi_def_cfa_register 5 subl $24, %esp movl $4, 4(%esp) movl $3, (%esp) call _Z3addii movl %eax, -4(%ebp) movl -4(%ebp), %eax leave .cfi_restore 5 .cfi_def_cfa 4, 4 ret .cfi_endproc .LFE1: .size _Z4initv, .-_Z4initv .ident "GCC: (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3" .section .note.GNU-stack,"",@progbits
函数默认以%eax作为返回值
看上面add函数的汇编代码,leave语句(即函数返回)的上一句代码:
addl %edx, %eax;即将a+b的值存到%eax寄存器中。接下来再看init中的下面两句汇编代码:
call _Z3addii;调用add函数,调用后%eax寄存器中的值就是add函数的返回值
movl %eax, -4(%ebp);将%eax寄存器的值存入局部变量a中
2.指针类型的返回值
int c = 0; int* add(int a, int b) { c = a + b; return &c; } int init() { int *a = add(3, 4); return *a; }
对应的汇编如下:
_Z3addii: .LFB0: .cfi_startproc pushl %ebp .cfi_def_cfa_offset 8 .cfi_offset 5, -8 movl %esp, %ebp .cfi_def_cfa_register 5 movl 12(%ebp), %eax movl 8(%ebp), %edx addl %edx, %eax movl %eax, c movl $c, %eax popl %ebp .cfi_def_cfa 4, 4 .cfi_restore 5 ret .cfi_endproc .LFE0: .size _Z3addii, .-_Z3addii .globl _Z4initv .type _Z4initv, @function _Z4initv: .LFB1: .cfi_startproc pushl %ebp .cfi_def_cfa_offset 8 .cfi_offset 5, -8 movl %esp, %ebp .cfi_def_cfa_register 5 subl $24, %esp movl $4, 4(%esp) movl $3, (%esp) call _Z3addii movl %eax, -4(%ebp) movl -4(%ebp), %eax movl (%eax), %eax leave .cfi_restore 5 .cfi_def_cfa 4, 4 ret .cfi_endproc
看上面的汇编可以发现,add函数利用语句:
movl $c, %eax;将全局变量c的地址赋值给%eax
init函数利用语句:
movl (%eax), %eax;将%eax寄存器值所代表的地址处的值赋值给%eax
3.引用类型的返回值
int c = 0; int& add(int a, int b) { c = a + b; return c; } int init() { int a = add(3, 4); return a; }
汇编代码如下:
_Z3addii: .LFB0: .cfi_startproc pushl %ebp .cfi_def_cfa_offset 8 .cfi_offset 5, -8 movl %esp, %ebp .cfi_def_cfa_register 5 movl 12(%ebp), %eax movl 8(%ebp), %edx addl %edx, %eax movl %eax, c movl $c, %eax popl %ebp .cfi_def_cfa 4, 4 .cfi_restore 5 ret .cfi_endproc .LFE0: .size _Z3addii, .-_Z3addii .globl _Z4initv .type _Z4initv, @function _Z4initv: .LFB1: .cfi_startproc pushl %ebp .cfi_def_cfa_offset 8 .cfi_offset 5, -8 movl %esp, %ebp .cfi_def_cfa_register 5 subl $24, %esp movl $4, 4(%esp) movl $3, (%esp) call _Z3addii movl (%eax), %eax movl %eax, -4(%ebp) movl -4(%ebp), %eax leave .cfi_restore 5 .cfi_def_cfa 4, 4 ret .cfi_endproc
看上面汇编会发现,add函数还是利用语句:
movl $c, %eax;将全局变量c的地址作为返回值。
但不同的是调用它的函数利用语句:
movl (%eax), %eax;访问到c的值然后赋值给%eax;
结论:由此可以发现,函数的返回值都是通过%eax来传递的,且指针类型和引用类型的返回值都是地址值