当前位置:编程学习 > C/C++ >>

C++愤恨者札记1——类对象作为函数参数的数据传递过程

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      &

补充:软件开发 , C++ ,
CopyRight © 2022 站长资源库 编程知识问答 zzzyk.com All Rights Reserved
部分文章来自网络,