通过一个简单的例子学习编译器是如何执行程序的

本文通过一个简单的C++程序,探讨编译器如何执行程序,展示了函数调用和对象内存结构。在VC6.0环境下,分析了main函数和get函数的汇编代码,解释了栈区操作、参数传递和对象大小计算,旨在揭示C++程序的内部工作原理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在vc6.0下做了个小实验,主要是想通过汇编代码来了解c++内存结构以及编译器是如何运行c++程序的,展现函数调用的具体过程,记得在实习时用vs2005也这样做了个程序,也认真剖析过。可能由于时间关系遗忘了许多vs下的汇编代码,所以感觉两个编译器是存在着区别的。下面就把上面这几点一一说明下。

我的源程序是这样的:

这是一个简单的不能再简单的程序了,很多人肯定不屑一顾,但是对于我这种菜鸟来说,能通过这段代码学习c++的内部原理,真的是受益匪浅了。不多说了,还是先看下对应的汇编代码吧:

代码说明:

main函数中声明了一个对象test,类型是xy,而xy又继承自x,类中各有几个属于对象的成员和类成员。

main函数中还调用了一个用户自定义的函数get函数,这个函数接受一个int型参数,并返回一个int型数据

main函数中还调用了一些标准c++函数库,还有一个关键字sizeof()。

代码运行说明:

在24行声明test对象之前,是操作系统调用main函数后进行的保存现场等操作,首先把bp压栈,此时的bp记录了调用main函数的函数栈的栈底指针,以便从main函数返回后知道上一个栈的起始地址;其次把 sp值赋给bp,表明此时的被调用函数栈(即main栈)的栈底指针是上一个函数栈的栈顶值;sp减50h表明了这个栈有多大空间;下面两行把si,di压栈,是保存了调用函数栈的源变址或目的变址的值的,否则从main函数返回时就会出现问题,即使不在这做保存,也肯定要在调用函数栈中保存;紧接着把[ebp-50h]的值赋给di,这个di就可以用来取各种操作数了吧(它的作用,我只是猜测,具体的作用是什么,我也不知道);剩下这几行一直到25行函数调用处我更加不知道是为什么,以后遇到高手指点后再补全吧。

25行开始是函数调用了,首先是一句压栈操作,把5压栈(从这我们可以知道,在这个编译器下,实参是在调用函数栈里保存的,据说有些是在被调用函数栈里保存的。。);然后是转到被调用函数里运行了,之后我们再说get函数栈,现在先假设get已经返回,那么sp指针要把5出栈,所以有了个esp+4,调用完,又接着下一个函数的调用,由于这些函数是系统函数,原理跟调用get函数一样,就不再多说,值得一说的是函数最后打印了个test对象的size,在此编译器下是12,由此引出c++对象的内存分配情况,简单的说,就是基类对象成员加上派生类对象成员的size,最后经过一定的对齐方式,得到最后的size;最后,所有函数都返回后,就是一些出栈操作,也就是所谓的恢复现场,到此,main函数也运行完毕。

下面说明下get函数的调用:

首先,看下对应的汇编代码:

代码说明:其实跟main函数栈的操作是一样的,都是保存各个寄存器的值,然后进行各种运算或者函数调用,最后在把结果返回,值得

一说的是在get函数返回时,是把ptr[ebp-4]的值保存在了eax中,而在我的印象中,还可以是在调用函数栈中申请一块内存,用以存放这个结果值。

在这个例子中,我们懂得了什么是栈区,当然还有必须有其他几个区的帮助才行;粗略知道c++对象的分配方式及对齐方式;基本懂得c++运行的过程;以后我们还应该知道多态的实现原理。

c++学习是个互相学习,分享并获得的过程,希望我,还有所有爱好c++的同学都能学的很好!

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值