函数返回值研究

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来传递的,且指针类型和引用类型的返回值都是地址值

猜你喜欢

转载自becomebetter.iteye.com/blog/2222241