函数返回值的方式

- [ ] 2022/3/1(此处讨论的不是返回值和返回指针/引用的情况,而是当返回不同数据长度,编译器是如何指定返回方式的

不同编译器,处理的情况不同,下面的分析是基于VS2019的msvc编译器:

  • 返回值长度小于4字节,通过一个寄存器带出被调函数的栈空间;
  • 返回值长度在4到8字节之间,通过两个寄存器带出;
  • 返回值长度大于8字节,通过产生临时量带出,因为寄存器已经没有足够的内存存放了;另外,该临时量是在函数被调用前就创建好,把其地址压入栈中,函数被调用时对临时量赋值

好,以下开始分析:

1)函数返回宽度为4字节的值时(如返回内置类型int或指针)

int func2()
{
	int a = 2;
	return a;
}
//在main中调用
	int aa = func2();
003E1A15  call        func1 (03E1217h)  
	
```c
int func2()
{
//此处忽略了开辟栈空间的汇编语句
	int a = 2;
003E1875  mov         dword ptr [a],2  
	return a;
003E187C  mov         eax,dword ptr [a]  
}
003E187F  pop         edi  
003E1880  pop         esi  
003E1881  pop         ebx  
003E1882  add         esp,0CCh  
003E1888  cmp         ebp,esp  
003E188A  call        __RTC_CheckEsp (03E1244h)  
003E188F  mov         esp,ebp  
003E1891  pop         ebp  
003E1892  ret  

003E1A1A mov dword ptr [aa],eax
``

  • 从以上代码可以看出,当返回值宽度为4字节,编译器会通过寄存器eax把值传回来赋给变量aa;

2)当返回值为结构体且宽度大于8字节

struct MyStruct
{
	int a;
	int b;
	int c;
	/*int d;
	int e;*/
};
struct MyStruct func1()
{
	MyStruct m1;
	m1.a = 9;
	m1.b = 8;
	m1.c = 7;
	/*m1.d = 6;
	m1.e = 5;*/
	return m1;
}

MyStruct m2 = func1();
003E1A1D  lea         eax,[ebp-114h]  
003E1A23  push        eax  
003E1A24  call        func1 (03E13B1h)  
//以下是func1函数里面的情况
			/*
			MyStruct m1;
				m1.a = 9;
			003E1985  mov         dword ptr [m1],9  
				m1.b = 8;
			003E198C  mov         dword ptr [ebp-0Ch],8  
				m1.c = 7;
			003E1993  mov         dword ptr [ebp-8],7  
				return m1;
				//下面的mov语句把返回的结构体变量的值拷贝到临时量的空间里面
			003E199A  mov         eax,dword ptr [ebp+8]  
			003E199D  mov         ecx,dword ptr [m1]  
			003E19A0  mov         dword ptr [eax],ecx  
			003E19A2  mov         edx,dword ptr [ebp-0Ch]  
			003E19A5  mov         dword ptr [eax+4],edx  
			003E19A8  mov         ecx,dword ptr [ebp-8]  
			003E19AB  mov         dword ptr [eax+8],ecx  
			003E19AE  mov         eax,dword ptr [ebp+8]  
			}
			*/

003E1A29  add         esp,4  
//以下语句:把临时量的数据拷贝回main空间的局部变量m2
003E1A2C  mov         ecx,dword ptr [eax]  
003E1A2E  mov         dword ptr [ebp-100h],ecx  
003E1A34  mov         edx,dword ptr [eax+4]  
003E1A37  mov         dword ptr [ebp-0FCh],edx  
003E1A3D  mov         eax,dword ptr [eax+8]  
003E1A40  mov         dword ptr [ebp-0F8h],eax  
003E1A46  mov         ecx,dword ptr [ebp-100h]  
003E1A4C  mov         dword ptr [m2],ecx  
003E1A4F  mov         edx,dword ptr [ebp-0FCh]  
003E1A55  mov         dword ptr [ebp-18h],edx  
003E1A58  mov         eax,dword ptr [ebp-0F8h]  
003E1A5E  mov         dword ptr [ebp-14h],eax  

从上面分析可知:函数返回结构体变量时,会在函数被调用前分配一段空间,先把该段空间的地址压栈,再开辟函数调用需要的栈空间,在被调函数中向该段空间赋上返回值,函数返回后,在main的栈空间再次从该段空间把数值拷贝回局部变量;

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值