其他语言

本类阅读TOP10

·基于Solaris 开发环境的整体构思
·使用AutoMake轻松生成Makefile
·BCB数据库图像保存技术
·GNU中的Makefile
·射频芯片nRF401天线设计的分析
·iframe 的自适应高度
·BCB之Socket通信
·软件企业如何实施CMM
·入门系列--OpenGL最简单的入门
·WIN95中日志钩子(JournalRecord Hook)的使用

分类导航
VC语言Delphi
VB语言ASP
PerlJava
Script数据库
其他语言游戏开发
文件格式网站制作
软件工程.NET开发
C++之研究——对象的实现(2)

作者:未知 来源:月光软件站 加入时间:2005-2-28 月光软件站

上次说了一个C++对象在内存中的实际形式,现在来说说C++中以对象为参数或返回值的函数是如何实现的。在此之前如果你对函数调用的汇编形式毫无概念的话可以先看看这篇文章:http://www.20cn.net/ns/wz/sys/data/20040208183412.htm

来看下面的代码:

class test   //sizeof(test) is 24
{
public:
 int m1;
 int m2;
 int m3;
 int m4;
 int m5;
 int m6;
};

test function1()
{
 test cls2;
 return cls2;  // Line 15
}

int function2(test temp)
{
 temp.m1=1;  // Line 20
 return 0;  // Line 21
}

int main()
{
 test cls1;
 cls1=function1(); // Line 27
 function2(cls1); // Line 28
 return 0;
}

由于VC编译的未优化代码和优化后的代码相差比较大,所以在编译时增加"/02"参数,使用命令行"cl test.cpp /Fa /02"对源文件进行编译。得到的中间汇编代码如下:

PUBLIC ?function1@@YA?AVtest@@XZ   ; function1
; COMDAT ?function1@@YA?AVtest@@XZ
_TEXT SEGMENT
_cls2$ = -24
$T295 = 8
?function1@@YA?AVtest@@XZ PROC NEAR   ; function1入口
; File main.cpp
; Line 15
 mov eax, DWORD PTR $T295[esp-4]  ; 将cls1的地址作为返回值保存到eax中
 sub esp, 24     ; 分配cls2的内存
 mov ecx, 6
 push esi
 push edi
 lea esi, DWORD PTR _cls2$[esp+32]
 mov edi, eax
 rep movsd     ; 将cls2对象复制到cls1中去
 pop edi
 pop esi
; Line 16
 add esp, 24     ; 00000018H
 ret 0
?function1@@YA?AVtest@@XZ ENDP    ; function1结束
_TEXT ENDS
PUBLIC ?function2@@YAHVtest@@@Z   ; function2
; COMDAT ?function2@@YAHVtest@@@Z
_TEXT SEGMENT
?function2@@YAHVtest@@@Z PROC NEAR   ; function2入口
; Line 21
 xor eax, eax    ; Line 20 的操作被优化掉了
; Line 22
 ret 0
?function2@@YAHVtest@@@Z ENDP    ; function2结束
_TEXT ENDS
PUBLIC _main
; COMDAT _main
_TEXT SEGMENT
$T301 = -24
_main PROC NEAR     ; COMDAT
; Line 25
 sub esp, 24     ; 分配cls1的内存空间
; Line 27
 lea eax, DWORD PTR $T301[esp+24]  ; 将cls1的地址送入eax寄存器
 push esi
 push edi
 push eax     ; 将cls1的地址作为参数传递给function1
 call ?function1@@YA?AVtest@@XZ  ; 调用function1
; Line 28
 sub esp, 20     ; 恢复堆栈并分配temp对象的空间(24-4=20)
 mov ecx, 6
 mov esi, eax
 mov edi, esp
 rep movsd     ; 将cls1对象复制到temp对象中去
 call ?function2@@YAHVtest@@@Z  ; 调用function2
 add esp, 24     ; 00000018H
; Line 29
 xor eax, eax
; Line 30
 pop edi
 pop esi
 add esp, 24     ; 00000018H
 ret 0
_main ENDP
_TEXT ENDS
END


先来看function1的调用过程:1)程序现在堆栈中给cls1分配了24字节的内存;然后将cls1的地址作为参数传递给function1;随后调用function1。2)进入function1中,程序先给cls2分配内存;然后程序将cls2对象复制到cls1中去;把cls1的地址作为返回值。

根据上述过程,"test function1();"的实际形式其实是:

test *function1(test *ptr_cls)
{
 test cls2;
 memcpy(ptr_cls,&cls2,sizeof(test));
 return ptr_cls;
}

而调用代码的实际形式是:

int main()
{
 test cls1;
 function1(&cls1);
 ... ...
 return 0;
}

再来看function2的调用过程:程序先给temp分配了一个24字节的对象;然后将cls1对象复制到temp对象中去;随后就调用function2。比起function1,function2要简单很多。

 




相关文章

相关软件