关于C++对象作为返回值汇编代码的问题

lishaoyu 2013-02-01 11:01:04
C++代码如下:

class CReturn
{
public:
int m_nNumber;
};

CReturn GetReturn()
{
CReturn RetObj;
RetObj.m_nNumber = 0;
return RetObj;
}

int main(int argc, char* argv[])
{
CReturn objA;
objA = GetReturn();
return 0;
}

其中main函数中的汇编代码如下:

29: CReturn objA;
30: objA = GetReturn();
004010BE lea eax,[ebp-84h] // 返回对象的栈空间首地址
004010C4 push eax // 将返回对象的首地址压入栈中,用于保存返回对象的数据
004010C5 call @ILT+0(GetReturn) (00401005)
004010CA add esp,4
004010CD mov esi,eax // 取出返回对象首址
004010CF mov ecx,0Bh
004010D4 lea edi,[ebp-58h]
004010D7 rep movs dword ptr [edi],dword ptr [esi] // 将返回对象放入ebp-58h栈空间中
004010D9 mov ecx,0Bh
004010DE lea esi,[ebp-58h]
004010E1 lea edi,[ebp-2Ch] // ebp-2Ch即局变量objA的地址
004010E4 rep movs dword ptr [edi],dword ptr [esi]
31: return 0;
004010E6 xor eax,eax


第3行已经用一个栈空间ebp-84h接收GetReturn返回的对象,为什么需要第7到10行再进行一次复制到ebp-58h栈空间里面,
然后再从栈空间ebp-58h再到栈空间ebp-2Ch(也就是局部变量objA),为什么不直接从ebp-84h到ebp-2Ch呢?
望大家不吝赐教!
GetReturn函数汇编代码如下:

16: CReturn RetObj;
17:
18: RetObj.m_nNumber = 0;
00401038 mov dword ptr [ebp-2Ch],0
19: for (int i = 0; i < 10; i++)
0040103F mov dword ptr [ebp-30h],0
00401046 jmp GetReturn+31h (00401051)
00401048 mov eax,dword ptr [ebp-30h]
0040104B add eax,1
0040104E mov dword ptr [ebp-30h],eax
00401051 cmp dword ptr [ebp-30h],0Ah
00401055 jge GetReturn+46h (00401066)
20: {
21: RetObj.m_nArray[i] = i + 1;
00401057 mov ecx,dword ptr [ebp-30h]
0040105A add ecx,1
0040105D mov edx,dword ptr [ebp-30h]
00401060 mov dword ptr [ebp+edx*4-28h],ecx
22: }
00401064 jmp GetReturn+28h (00401048)
23:
24: return RetObj;
00401066 mov ecx,0Bh
0040106B lea esi,[ebp-2Ch]
0040106E mov edi,dword ptr [ebp+8] // 这里的ebp+8即main函数中的ebp-84h
00401071 rep movs dword ptr [edi],dword ptr [esi]
00401073 mov eax,dword ptr [ebp+8] // 将返回对象首地址放入eax中
25: }
...全文
484 11 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
11 条回复
切换为时间正序
请发表友善的回复…
发表回复
vcvycy 2015-09-30
  • 打赏
  • 举报
回复
遇到同样的问题了。 仔细看了回复还是没懂: 没有加构造函数和析构函数,会出现2次复制,84h->58h,58h->2ch. 但是加了构造函数函数和析构函数,只是复制一次 004011F1 mov dword ptr [ebp-0BCh],eax // eax其实保存的就是临时对象首地址(ebp-0B4h) 004011F7 mov esi,dword ptr [ebp-0BCh] // 临时对象地址作为源 004011FD mov ecx,15h 00401202 lea edi,[ebp-60h] // objA对象地址作为目的地 00401205 rep movs dword ptr [edi],dword ptr [esi] // 拷贝即对象复制 。那为什么第一个要复制2次呢?
lishaoyu 2013-02-04
  • 打赏
  • 举报
回复
引用 9 楼 BoweirrKing 的回复:
对啊,就应该是这个样子的啊。不过,你要搞清楚,调用的都是哪个对象的函数。 Assembly code?12lea eax,[ebp-0B4h] // 临时对象栈空间 <---这个就是我说的那个你看不到的中间对象call @ILT+5(GetReturn) (0040100a)// 调用GetReturn函数<---这个调用的是隐藏的中间对象的GetReturn函数……
BoweirrKing 2013-02-02
  • 打赏
  • 举报
回复
对啊,就应该是这个样子的啊。不过,你要搞清楚,调用的都是哪个对象的函数。 [code=ASM]lea eax,[ebp-0B4h] // 临时对象栈空间 <---这个就是我说的那个你看不到的中间对象 call @ILT+5(GetReturn) (0040100a)// 调用GetReturn函数<---这个调用的是隐藏的中间对象的GetReturn函数[/code] 再接下来的就是把这个隐藏的CReturn对象复制到你的局部变量 objA 中.
lishaoyu 2013-02-01
  • 打赏
  • 举报
回复
引用 7 楼 BoweirrKing 的回复:
你把你的CReturn类改成这样的 class CReturn { public: CReturn(){printf("CReturn()...\n");memset(m_Array,0,sizeof(m_Array));} ~CReturn(){printf("~CReturn()...\n");} int m_nNumber; i……
感谢BoweirrKing,看下你举例对应的汇编

17:       CReturn objA;
004011D3   lea         ecx,[ebp-60h] // objA对象首地址
004011D6   call        @ILT+0(CReturn::CReturn) (00401005) // 调用构造函数
004011DB   mov         dword ptr [ebp-4],0
18:       objA = GetReturn();
004011E2   lea         eax,[ebp-0B4h]  // // 临时对象栈空间
004011E8   push        eax
004011E9   call        @ILT+5(GetReturn) (0040100a) // 调用GetReturn函数
004011EE   add         esp,4
004011F1   mov         dword ptr [ebp-0BCh],eax // eax其实保存的就是临时对象首地址(ebp-0B4h)
004011F7   mov         esi,dword ptr [ebp-0BCh] // 临时对象地址作为源
004011FD   mov         ecx,15h
00401202   lea         edi,[ebp-60h] // objA对象地址作为目的地
00401205   rep movs    dword ptr [edi],dword ptr [esi] // 拷贝即对象复制
00401207   lea         ecx,[ebp-0B4h]
0040120D   call        @ILT+15(CReturn::~CReturn) (00401014) // 最后临时对象析构
BoweirrKing 2013-02-01
  • 打赏
  • 举报
回复
你把你的CReturn类改成这样的 class CReturn { public: CReturn(){printf("CReturn()...\n");memset(m_Array,0,sizeof(m_Array));} ~CReturn(){printf("~CReturn()...\n");} int m_nNumber; int m_Array[20]; };
jimette 2013-02-01
  • 打赏
  • 举报
回复
lz 还是去汇编专区学习汇编好点!
lishaoyu 2013-02-01
  • 打赏
  • 举报
回复
引用 3 楼 BoweirrKing 的回复:
有一点楼主需要了解的是,在直接返回对象的函数中,有一个你看不到的,位于栈上的对象的构造再销毁的过程。 你用做例子的这个类太特殊了,或者说太简单了,你弄一个复杂一点的类试试看,在你所说的“两次复制”之间,一定会有相关的代码出现。
能举个详细点的例子说明下么?
jimette 2013-02-01
  • 打赏
  • 举报
回复
引用 1 楼 zhao4zhong1 的回复:
改为
C/C++ code?1234567891011121314151617181920class CReturn{public: int m_nNumber;}; CReturn GetReturn(){ CReturn RetObj; RetObj.m_nNumber = 0; return RetObj;} int main(int ……


什么都没有!
BoweirrKing 2013-02-01
  • 打赏
  • 举报
回复
有一点楼主需要了解的是,在直接返回对象的函数中,有一个你看不到的,位于栈上的对象的构造再销毁的过程。 你用做例子的这个类太特殊了,或者说太简单了,你弄一个复杂一点的类试试看,在你所说的“两次复制”之间,一定会有相关的代码出现。
lishaoyu 2013-02-01
  • 打赏
  • 举报
回复
引用 1 楼 zhao4zhong1 的回复:
改为 C/C++ code?1234567891011121314151617181920class CReturn{public: int m_nNumber;}; CReturn GetReturn(){ CReturn RetObj; RetObj.m_nNumber = 0; return RetObj;} int main(int ……
感谢赵老师,我先把你说的对应的汇编代码贴出来

49:   __asm int 3
004010B8   int         3
50:       CReturn objA;
51:       objA = GetReturn();
004010B9   call        @ILT+0(GetReturn) (00401005)
004010BE   mov         dword ptr [ebp-8],eax
004010C1   mov         eax,dword ptr [ebp-8]
004010C4   mov         dword ptr [ebp-4],eax

第6行到第8行,为什么搞得这么麻烦,把第6行到第8行换成mov dword ptr [ebp-4],eax(也就是去掉第6、7行) 不也可以么,干嘛要搞个ebp-8作为中转呢?
赵4老师 2013-02-01
  • 打赏
  • 举报
回复
改为
class CReturn
{
public:
    int m_nNumber;
};
 
CReturn GetReturn()
{
    CReturn RetObj;
    RetObj.m_nNumber = 0;
    return RetObj;
}
 
int main(int argc, char* argv[])
{
__asm int 3
    CReturn objA;
    objA = GetReturn();
    return 0;
}
编译为Release版,按F5,Alt+8,再看对应汇编。

16,547

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC相关问题讨论
社区管理员
  • 基础类社区
  • AIGC Browser
  • encoderlee
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

        VC/MFC社区版块或许是CSDN最“古老”的版块了,记忆之中,与CSDN的年龄几乎差不多。随着时间的推移,MFC技术渐渐的偏离了开发主流,若干年之后的今天,当我们面对着微软的这个经典之笔,内心充满着敬意,那些曾经的记忆,可以说代表着二十年前曾经的辉煌……
        向经典致敬,或许是老一代程序员内心里面难以释怀的感受。互联网大行其道的今天,我们期待着MFC技术能够恢复其曾经的辉煌,或许这个期待会永远成为一种“梦想”,或许一切皆有可能……
        我们希望这个版块可以很好的适配Web时代,期待更好的互联网技术能够使得MFC技术框架得以重现活力,……

试试用AI创作助手写篇文章吧