c++ 简单对象的内存分配过程

来源:互联网 发布:通达即时通讯端口 编辑:程序博客网 时间:2024/05/30 02:52
</pre><h3></h3><h3><strong></strong><pre name="code" class="cpp">#include<iostream>#include"stde.h"using namespace std;void ff_j_x(){char ss[10] = "dsfg";stde d(10, ss);d.shuchu();cout << &d<<&ss << endl;}int main(){ff_j_x();getchar();return 0;}//stde.h#pragma onceclass stde{  public:stde();stde(int, char*);~stde();void shuchu();  private:int age;char name[20];};//stde.cpp:#include "stde.h"#include<string.h>#include<iostream>using namespace std;stde::stde() :age(0){}stde::stde(int age, char* nname){strcpy_s(name, nname);this->age = age;}stde::~stde(){cout << "xi gou han shu!" << endl;}void stde::shuchu(){cout << this->age <<  this->name << endl;}


//调用函数ff_j_x在栈中创建(局部变量)对象d;调用其构造函数,输出函数。

<pre name="code" class="cpp">vs2013下反汇编:

void ff_j_x()
{
00A562A1 sub esp,0F8h
00A562A7 push ebx
00A562A8 push esi
00A562A9 push edi
00A562AA lea edi,[ebp-104h]
00A562B0 mov ecx,3Eh
00A562B5 mov eax,0CCCCCCCCh
00A562BA rep stos dword ptr es:[edi]
00A562BC mov eax,dword ptr ds:[00A60000h]
00A562C1 xor eax,ebp
00A562C3 mov dword ptr [ebp-10h],eax
00A562C6 push eax
00A562C7 lea eax,[ebp-0Ch]
00A562CA mov dword ptr fs:[00000000h],eax
char ss[10] = "dsfg";
00A562D0 mov eax,dword ptr ds:[00A5DDA8h] //(内存中)00A5DDA8h A8 64 73 66 67 00 00 00 00 28 00 dsfg....(.
00A562D5 mov dword ptr [ss],eax //dsfg占4字节内存 (dword ptr ) 把dsfg存入数组
00A562D8 mov cl,byte ptr ds:[0A5DDACh]
00A562DE mov byte ptr [ebp-1Ch],cl //dsfg后面补'\0'
00A562E1 xor eax,eax
00A562E3 mov dword ptr [ebp-1Bh],eax
00A562E6 mov byte ptr [ebp-17h],al //其余空间置0
stde d(10, ss);
00A562E9 lea eax,[ss] //参数ss进栈
00A562EC push eax //
00A562ED push 0Ah //参数10进栈
00A562EF lea ecx,[d] //取对象d的首地址存入ecx(即传入this指针)>>>>>(由此可知this指针不占内存)
00A562F2 call stde::stde (0A513EDh) //调用类的构造函数
00A562F7 mov dword ptr [ebp-4],0
d.shuchu();
00A562FE lea ecx,[d] //传入this指针
00A56301 call stde::shuchu (0A5145Bh) //调用类的输出函数
cout << &d<<&ss << endl;
00A56306 mov esi,esp
cout << &d<<&ss << endl;
00A56308 push 0A513FCh
00A5630D mov edi,esp
00A5630F lea eax,[ss] //取ss的首地址存入eax寄存器
00A56312 push eax //ss首地址进栈
00A56313 mov ebx,esp
00A56315 lea ecx,[d] //取d的首地址存入ecx寄存器(this指针)
00A56318 push ecx //d的首地址进栈
00A56319 mov ecx,dword ptr ds:[0A610A0h]
00A5631F call dword ptr ds:[0A61100h]
00A56325 cmp ebx,esp
00A56327 call __RTC_CheckEsp (0A51343h)
00A5632C mov ecx,eax
00A5632E call dword ptr ds:[0A61100h]
00A56334 cmp edi,esp
00A56336 call __RTC_CheckEsp (0A51343h)
00A5633B mov ecx,eax
00A5633D call dword ptr ds:[0A61090h]
00A56343 cmp esi,esp
00A56345 call __RTC_CheckEsp (0A51343h)
}
00A5634A mov dword ptr [ebp-4],0FFFFFFFFh
00A56351 lea ecx,[d] //传递this指针
00A56354 call stde::~stde (0A511F4h) //调用析构函数
00A56359 push edx
00A5635A mov ecx,ebp
00A5635C push eax
00A5635D lea edx,ds:[0A56394h]
00A56363 call @_RTC_CheckStackVars@8 (0A51136h)
00A56368 pop eax
00A56369 pop edx
00A5636A mov ecx,dword ptr [ebp-0Ch]
00A5636D mov dword ptr fs:[0],ecx
00A56374 pop ecx
00A56375 pop edi
00A56376 pop esi
00A56377 pop ebx
00A56378 mov ecx,dword ptr [ebp-10h]
00A5637B xor ecx,ebp
00A5637D call @__security_check_cookie@4 (0A51041h)
00A56382 add esp,104h
00A56388 cmp ebp,esp
00A5638A call __RTC_CheckEsp (0A51343h)
00A5638F mov esp,ebp
00A56391 pop ebp
00A56392 ret
00A56393 nop
00A56394 add al,byte ptr [eax]
00A56396 add byte ptr [eax],al
00A56398 pushfd
00A56399 arpl word ptr [ebp-2000h],sp
00A5639F dec dword ptr [edx]
00A563A1 add byte ptr [eax],al
00A563A3 add byte ptr [esi-3FFF5A9Dh],dh
00A563A9 ?? ??
00A563AA ?? ??
00A563AB call fword ptr [eax]
00A563AD add byte ptr [eax],al
00A563AF add byte ptr [ebx+6400A5h],dh
00A563B6 jae std::uncaught_exception+1h (0A5642Bh)
00A563B8 add ah,cl
构造函数的调用过程:
stde::stde(int age, char* nname)
{
00A53E0C push ecx //ecx存放有this指针 (由 void ff_j_x() 函数的 00F2630F lea ecx,[d] 可知)
00A53E0D lea edi,[ebp-0CCh]
00A53E13 mov ecx,33h
00A53E18 mov eax,0CCCCCCCCh //33*4=cch字节空间初始化为值cc
00A53E1D rep stos dword ptr es:[edi]
00A53E1F pop ecx
00A53E20 mov dword ptr [this],ecx //保存ecx的值到this指针
strcpy_s(name, nname);
00A53E23 mov eax,dword ptr [nname]
00A53E26 push eax
00A53E27 mov ecx,dword ptr [this]
00A53E2A add ecx,4
00A53E2D push ecx
00A53E2E call strcpy_s<20> (0A51069h)
00A53E33 add esp,8
this->age = age;
00A53E36 mov eax,dword ptr [this]
00A53E39 mov ecx,dword ptr [age]
00A53E3C mov dword ptr [eax],ecx
}
00A53E3E mov eax,dword ptr [this]
00A53E41 pop edi
00A53E42 pop esi
00A53E43 pop ebx
00A53E44 add esp,0CCh
00A53E4A cmp ebp,esp
00A53E4C call __RTC_CheckEsp (0A51343h)
00A53E51 mov esp,ebp
00A53E53 pop ebp
00A53E54 ret 8

第一次调试:
+ss0x0035f9cc "dsfg"char[10]
+d{age=-858993460 name=0x0035f9b0 "烫烫烫烫烫烫烫烫烫烫 }stde
                                   &d=0x0035f9b0-4=0x0035f9ac
                                  ECX?=?0035F9AC (d.age的地址)     
                                 ECX存放的是this指针, 说名this指针就是对象首元素的地址。
第二次调试:
+ss0x0045f744 "dsfg"char[10]
+d{age=-858993460 name=0x0045f728 "烫烫烫烫烫烫烫烫烫烫 }stde
                                  &d=0x0045f724;
                                  this==0x0045f724(即ECX=0x0045f724);
00A53E3E  mov         eax,dword ptr [this]   //返回值存放在EAX寄存器  所以是返回this指针   
(void ff_j_x()原函数没有返回值  但是this指针是默认返回的)
00A53E41  pop         edi  
00A53E42  pop         esi  
00A53E43  pop         ebx  
00A53E44  add         esp,0CCh  
00A53E4A  cmp         ebp,esp  
00A53E4C  call        __RTC_CheckEsp (0A51343h)     



00A56351 lea ecx,[d] //传递this指针
00A56354 call stde::~stde (0A511F4h) //调用析构函数

由于对象d是在ff_j_x()函数的栈空间中分配的,当ff_j_x()结束时,该函数的所有栈空间都被释放,
所以该函数在退出时会调用对象的析构函数来释放掉对象d,这是在编译的时候,编译器加上去的。

0x0045f724:     0a 00 00 00 64 73 66 67 00 fe fe fe fe fe fe fe fe fe fe fe fe fe fe fe cc cc cc cc cc cc cc cc 

这是对象d在栈中的存储情况; d.age=0x0000000a(十进制:10) d.name = 0x67667364(字符:dsfg)

说明对象的内存分配是先定义先分配

本例中:
  private:int age;char name[20];
age是先定义的 , name是最后定义的 , 所以创建对象时会先给age分配内存再给name分配内存。也就是说age的栈内存地址低于name的栈内存地址

0x0045f724:  

(相对栈顶)

(低地址)  0a 00 00 00(age)64 73 66 67 00(name) fe fe fe fe fe fe fe fe fe fe fe fe fe fe fe cc cc cc cc cc cc

cc cc(高地址)

(相对栈低)



下面用一段新代码进行该问题的讨论:
</pre><pre name="code" class="cpp"><pre name="code" class="cpp">//Abc.h#pragma onceclass Abc{public:Abc(int, int , int );void Show();~Abc();private:int x;int y;const int i;const int j;};//Abc.cpp#include "Abc.h"#include<iostream>using namespace std;Abc::Abc(int a, int b, int c) :j(a), i(j), y(x), x(b){}void Abc::Show(){cout <<"x = "<< x << "  " <<"y = "<< y << "  " <<"i = "<< i << "  "<<"j = " << j << endl;}Abc::~Abc(){}void f(){Abc a(1, 2, 3);a.Show();}//main()#include "Abc.h"#include<iostream>using namespace std;int main(){f();getchar();return 0;}

//运行结果:   x = 1  y = 1  i = -858993460  j = 2

证明 :j(a), i(j), y(x), x(b) 是先给x赋值x=b=1;  然后是y=x=1; 再到i=j=?;最后是j=a=2;

VS2013反汇编: void f() 013E66C4  add         byte ptr [eax-33333334h],bh   013E66CA  rep stos    dword ptr es:[edi]   013E66CC  mov         eax,dword ptr ds:[013F0000h]   013E66D1  xor         eax,ebp   013E66D3  mov         dword ptr [ebp-10h],eax   013E66D6  push        eax   013E66D7  lea         eax,[ebp-0Ch]   013E66DA  mov         dword ptr fs:[00000000h],eax   Abc a(1, 2, 3); 013E66E0  push        3  013E66E2  push        2   013E66E4  push        1   013E66E6  lea         ecx,[a]   013E66E9  call        Abc::Abc (013E1046h)   013E66EE  mov         dword ptr [ebp-4],0   a.Show(); 013E66F5  lea         ecx,[a]   013E66F8  call        Abc::Show (013E105Ah)   } Abc::Abc(int a, int b, int c) :j(b), i(j), y(x), x(a) 013E3AD0  push        ebp   013E3AD1  mov         ebp,esp   013E3AD3  sub         esp,0CCh   013E3AD9  push        ebx  013E3ADA  push        esi   013E3ADB  push        edi   013E3ADC  push        ecx   013E3ADD  lea         edi,[ebp-0CCh]   013E3AE3  mov         ecx,33h   013E3AE8  mov         eax,0CCCCCCCCh   013E3AED  rep stos    dword ptr es:[edi]   013E3AEF  pop            ecx                                 //this指针 013E3AF0  mov         dword ptr [this],ecx           

x(b):

013E3AF3  mov         eax,dword ptr [this]                   //eax存放this指针 

013E3AF6  mov         ecx,dword ptr [b]                      //ecx存放a的值013E3AF9  mov         dword ptr [eax],ecx                    //把a存入this指向的开始位置 

y(x):

013E3AFB  mov         eax,dword ptr [this]                   //eax存放this指针013E3AFE  mov         ecx,dword ptr [this]                   //ecx存放this指针013E3B01  mov         edx,dword ptr [ecx]                    //把ecx(即x的值)赋给edx013E3B03  mov         dword ptr [eax+4],edx                  //edx赋值给this+4的地址空间(即y);

i(j):

013E3B06  mov         eax,dword ptr [this]                   //this指针存入eax013E3B09  mov         ecx,dword ptr [this]                   //this指针存入ecx013E3B0C  mov         edx,dword ptr [ecx+0Ch]           //j的值赋值给edx013E3B0F  mov         dword ptr [eax+8],edx               //edx赋值给i

j(a):

013E3B12  mov         eax,dword ptr [this]                   //this指针存入eax 

013E3B15  mov         ecx,dword ptr [a]                      //形参b的值存入ecx013E3B18  mov         dword ptr [eax+0Ch],ecx         //ecx赋值给j}013E3B1B  mov         eax,dword ptr [this] 

实验结果也证明了:

j(a), i(j), y(x), x(b) 是先给x赋值x=b=1;  然后是y=x=1; 再到i=j=?;最后是j=a=2;

编译环境:VS2013 2015/06/12
                                             
0 0
原创粉丝点击