程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> C++憤恨者札記1——類對象作為函數參數的數據傳遞過程

C++憤恨者札記1——類對象作為函數參數的數據傳遞過程

編輯:C++入門知識

C++憤恨者札記1——類對象作為函數參數的數據傳遞過程
    C++繁雜的機制,加上枯燥的教科書,再加上無法回避地要使用它,注定要造就一批C++憤恨者。本文作為C++憤恨者札記系列第一篇,從匯編角度,觀察類對象作為函數參數時的數據傳遞過程。
    若沒有特殊說明,編譯器使用的是VC++,反匯編使用的是Windbg.下面是它們的版本號:
    Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 15.00.30729.01 for 80x86

    Microsoft (R) Windows Debugger Version 6.11.0001.404 X86

測試代碼如下:
[cpp] 
class Node 

public: 
    Node(){} 
    //Node(Node& n); 
    int data1; 
    int data2; 
    int data3; 
    int data4; 
    int data5; 
    int data6; 
    int data7; 
}; 
 
//Node::Node(Node &n) 
//{ 
//} 
 
void Fn( int a, Node n, int  b ) 

    n.data1 = 100; 
    n.data2 = 100; 
    a = 100; 
    b = 10; 

 
void main() 

    Node n; 
    Fn(1, n, 2); 

--------------------------------------------------
未使用拷貝構造函數時,調用Fn的反匯編代碼:

[plain]
00fa1421 6a02            push    2      ;第三個參數入棧 
 
00fa1423 83ec1c          sub     esp,1Ch    ;為Node n分配棧內存, 注意,構造函數Node(),並沒調用 
 
00fa1426 b907000000      mov     ecx,7      ;rep循環次數 
00fa142b 8d75e0          lea     esi,[ebp-20h]  ;Node n地址 
00fa142e 8bfc            mov     edi,esp    ;棧空間地址 
00fa1430 f3a5            rep movs dword ptr es:[edi],dword ptr [esi]    ;把n內容拷貝到棧空間上 
                                    ;A5 MOVS m32, m32 Move doubleword  
                                    ;at address DS:(E)SI to address ES:(E)DI 
 
00fa1432 6a01            push    1      ;第一個參數入棧 
 
00fa1434 e8a2fdffff      call    hello!ILT+470(?FnYAXHVNodeHZ) (00fa11db) 
 
00fa1439 83c424          add     esp,24h    ;恢復棧平衡,4+1CH+4=24H 

類對象參數位於棧上,是通過sub esp size來分配的。數據是通過內存拷貝來初始化。

--------------------------------------------------
使用拷貝構造函數時,即上面代碼把注釋去掉,調用Fn的反匯編代碼:
[plain] 
01002406 6a02            push    2      ;第三個參數入棧 
 
01002408 83ec1c          sub     esp,1Ch    ;開辟棧空間 
 
0100240b 8bcc            mov     ecx,esp    ;棧內存首址保存在ecx中,拷貝構造函數的this指針 
0100240d 8d45e0          lea     eax,[ebp-20h]  ;實參地址 
01002410 50              push    eax        ;作為拷貝構造函數的參數 
01002411 e8d4edffff      call    hello!ILT+485(??0NodeQAEAAV0Z) (010011ea)  ;拷貝構造函數,替換了rep movs內存拷貝 
 
01002416 6a01            push    1      ;第一個參數入棧 
01002418 e8beedffff      call    hello!ILT+470(?FnYAXHVNodeHZ) (010011db) 
0100241d 83c424          add     esp,24h    ;恢復棧平衡 

類參數仍然位於棧上,也是通過sub esp size來分配的。數據是通過拷貝構造函數初始化的,C++的機制就是繁多--||。

--------------------------------------------------
下面是Fn的反匯編結果,它可不管Node n是怎麼初始化的,只要把它在棧上的位置找到就OK啦。

[plain] 
hello!Fn: 
00a41a60 55              push    ebp                         | old ebp     |  ebp 
00a41a61 8bec            mov     ebp,esp                     |-------------| 
                                                             | ret address |  ebp+4 
00a41a63 81ecc0000000    sub     esp,0C0h                    |-------------| 
                                                             | int a       |  ebp+8 
00a41a69 53              push    ebx                         |-------------| 
00a41a6a 56              push    esi                         | Node n      |  ebp+0CH 
00a41a6b 57              push    edi                         |-------------| 
                                                             | int b       |  ebp+28H 
00a41a6c 8dbd40ffffff    lea     edi,[ebp-0C0h] 
00a41a72 b930000000      mov     ecx,30h 
00a41a77 b8cccccccc      mov     eax,0CCCCCCCCh 
00a41a7c f3ab            rep stos dword ptr es:[edi]    ;以是為局部變量空間初始化,debug版特有的 
 
00a41a7e c7450c64000000  mov     dword ptr [ebp+0Ch],64h    ;n.data1 = 100; 顯示ebp+0Ch是參數n的起始地址 
00a41a85 c7451064000000  mov     dword ptr [ebp+10h],64h    ;n.data2 = 100; 
00a41a8c c7450864000000  mov     dword ptr [ebp+8],64h      ;a = 100; 
00a41a93 c745280a000000  mov     dword ptr [ebp+28h],0Ah    ;b = 10; 
 
00a41a9a 5f              pop     edi 
00a41a9b 5e              pop     esi 
00a41a9c 5b              pop     ebx 
 
00a41a9d 8be5            mov     esp,ebp 
00a41a9f 5d              pop     ebp 
00a41aa0 c3              ret 

--------------------------------------------------
總結:
    類對象做為函數參數時,是被存放在棧上的,不影響實參的數據。
    若未重寫拷貝構造函數,類的其它構造函數將不會被調用。形參的數據是通過內存拷貝傳遞的。若重寫了,拷貝構造函數將會在初始化形參時被調用,不再進行內存拷貝工作。

 

作者:tms_li

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved