函数返回大类型方式

在函数调用中,返回值如果是内置类型,由于比较小,为了速度快,通常使用eax,edx传递32位,64位返回值,当返回值类型较大时


注意,实现方式可以是任意的,这里只简单探究其中一种实现方式,来大概有个映像,可以明白,在函数调用中一般是个什么概念,但并非绝对,但估计也都差不多.

struct MyStruct
{
	int SomeInt[0x20];
};

MyStruct GetStruck(int a, int b)
{
	MyStruct m{};
	return m;
}
int _tmain( int argc, _TCHAR* argv[] )
{
	//argv;
	//argc;

	MyStruct k = GetStruck( 1, 2 );

	return 0;
}


其,实现方式是

MyStruct* GetStruck( MyStruct* Result, int a, int b )
{
	MyStruct m{};
	//没办法使用Result的,否则就可以省略掉 m 到 Result的拷贝
	//return 进行赋值拷贝,Result是作为一个安全内存区域所使用,甚至连返回值都不是
	*Result = m;
	return Result;
}

int _tmain( int argc, _TCHAR* argv[] ){
	//调用以前开辟一块安全内存区域,没办法使用临时变量Temp,否则就可以省略掉 Temp 到 ReturnValue的拷贝
	MyStruct Temp;
	//另开辟内存存储返回值或函数表达式的值,总之此处还有一次拷贝
	MyStruct ReturnValue = *GetStruck( &Temp, 1, 2 );
	//再次拷贝到我们的变量中
	MyStruct k = ReturnValue;return 0;
}


 

即,返回值的内存由调用函数开辟,将其地址作为第一个参数传递给被调函数,在被掉函数中无法直接使用此返回变量(即第一个参数)只能当return 时 拷贝变量到此返回变量中,虽然确实存在第一个参数,但是我们没有其名字,无法直接使用,唯一的使用机会就是当return语句时,可以赋值初始化(或直接列表初始化?),被调函数返回利用返回的Result再次拷贝一份作为自己表达式的值,一共发生了3次拷贝

尝试使用引用来减少拷贝次数发现竟然是一样的

const MyStruct& k = GetStruck( 1, 2 );

//竟然等同于
MyStruct k = GetStruck( 1, 2 );
MyStruct &p = k;

//依然是3次拷贝

然后是测试右值引用,依然是3次拷贝


相关测试汇编

MyStruct GetStruck(int a, int b)
{
00188660  push        ebp  
00188661  mov         ebp,esp  
00188663  sub         esp,14Ch  
00188669  push        ebx  
0018866A  push        esi  
0018866B  push        edi  
0018866C  lea         edi,[ebp-14Ch]  
00188672  mov         ecx,53h  
00188677  mov         eax,0CCCCCCCCh  
0018867C  rep stos    dword ptr es:[edi]  
0018867E  mov         eax,dword ptr ds:[00196000h]  
00188683  xor         eax,ebp  
00188685  mov         dword ptr [ebp-4],eax  
	MyStruct m{};
00188688  push        80h  
0018868D  push        0  
0018868F  lea         eax,[m]  
00188695  push        eax  
00188696  call        _memset (017132Fh)  
0018869B  add         esp,0Ch  
	return m;
0018869E  mov         ecx,20h  
001886A3  lea         esi,[m]  
001886A9  mov         edi,dword ptr [ebp+8]  
001886AC  rep movs    dword ptr es:[edi],dword ptr [esi]  
001886AE  mov         eax,dword ptr [ebp+8]  
}






//_____________________________



00F38752  push        eax  
00F38753  call        GetStruck (0F214E2h)  
00F38758  add         esp,0Ch  
00F3875B  mov         ecx,20h  
00F38760  mov         esi,eax  
00F38762  lea         edi,[ebp-1DCh]  
00F38768  rep movs    dword ptr es:[edi],dword ptr [esi]  
00F3876A  mov         ecx,20h  
00F3876F  lea         esi,[ebp-1DCh]  
00F38775  lea         edi,[ebp-94h]  
00F3877B  rep movs    dword ptr es:[edi],dword ptr [esi]  
00F3877D  lea         ecx,[ebp-94h]  
00F38783  mov         dword ptr [k],ecx  

//__________________________________________________________

	MyStruct k = GetStruck( 1, 2 );
00A1874A  push        1  
00A1874C  lea         eax,[ebp-264h]  
00A18752  push        eax  
00A18753  call        GetStruck (0A014E2h)  
00A18758  add         esp,0Ch  
00A1875B  mov         ecx,20h  
00A18760  mov         esi,eax  
00A18762  lea         edi,[ebp-1DCh]  
00A18768  rep movs    dword ptr es:[edi],dword ptr [esi]  
00A1876A  mov         ecx,20h  
00A1876F  lea         esi,[ebp-1DCh]  
00A18775  lea         edi,[k]  
00A1877B  rep movs    dword ptr es:[edi],dword ptr [esi]  
	MyStruct &p = k;
00A1877D  lea         eax,[k]  
00A18783  mov         dword ptr [p],eax  
//__________________________________________________________




	MyStruct&& k = GetStruck( 1, 2 );
0018874A  push        1  
0018874C  lea         eax,[ebp-264h]  
00188752  push        eax  
00188753  call        GetStruck (01714E2h)  
00188758  add         esp,0Ch  
0018875B  mov         ecx,20h  
00188760  mov         esi,eax  
00188762  lea         edi,[ebp-1DCh]  
00188768  rep movs    dword ptr es:[edi],dword ptr [esi]  
0018876A  mov         ecx,20h  
0018876F  lea         esi,[ebp-1DCh]  
00188775  lea         edi,[ebp-94h]  
0018877B  rep movs    dword ptr es:[edi],dword ptr [esi]  
0018877D  lea         ecx,[ebp-94h]  
00188783  mov         dword ptr [k],ecx  

//__________________________________________________________


补充测试

GetStruck( 1, 2 ); 也会调用2次拷贝,被掉函数内一次,函数返回在主调函数内又一次.

int a = GetStruck( 1, 2 ).SomeInt[3];  也是拷贝2次,证明,第一次是进入被调函数分配使用的内存,第二次是返回值或表达式值的概念.

至于通过MyStruct &&a 或者 MyStruct a 来接收 返回值,还会进行一次拷贝,

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值