C从汇编代码角度理解类和对象提供的命名空间地址偏移
假设对某一个小问题的代码有两个写法A,B,其中A使用较简单的语法,需要写较多的代码;B使用较抽象的语法,只需要写较少的代码。B使用的语法是对A使用的语法的抽象,称为语法糖,其中的对应关系由编译器来实现,如:intarr〔5〕{1,2,3};arr〔2〕33;(arr2)33;可以理解为前一种写法是后一种写法的语法糖
我们知道,从机器语言到汇编语言到高级语言,实现了逐层抽象,中间的翻译工作由翻译程序汇编器和编译器来实现。高层抽象可以理解为低层抽象的语法糖。
一定程度上,面向对象可以理解为面向过程的语法糖,或者说,两者只是组织代码的方式发生了变化而已,数据可以聚合到结构体或类,而函数以结构体为参数,或函数隐含一个this指针做参数,指向类对象(当然,这里是就抽象和封装而言,类还提供更多的功能,如RAII,继承,多态,RTTI等):includeiostreamusingnamespacestd;角色c1长方形接口定义者,可放到头文件,使用文件来区分模块structCRect{intlenth;intwidth;};intarea(structCRectcr);角色c2长方形接口实现者,可以放到实现文件intarea(structCRectcr){returncrlenthcrwidth;}角色c3长方形接口使用者,可以放到使用文件intcalc(){structCRectcr;cr。lenth0x20;cr。width0x10;intararea(cr);returnar;}角色cpp1长方形接口定义者,可放到头文件,使用文件和类来区分模块classCppRect{public:intlenth;intwidth;intarea();};角色cpp2长方形接口实现者,可以放到实现文件intCppRect::area(){returnlenthwidth;}角色cpp3长方形接口使用者,可以放到使用文件intcalc2(){CppRectcr;cr。lenth0x20;cr。width0x10;intarcr。area();returnar;}intmain(){printf(usingstruct:rectsareaisd,calc());printf(usingclass:rectsareaisd,calc2());while(1);return0;}usingstruct:rectsareais512usingclass:rectsareais512
从以上实例可见,数据的聚合没有区别,都是由结构体变量或类对象提供一个基地址,而数据成员提供一个相对于基地址的偏移。处理结构体的全局函数以结构体变量或指针为参数,而类的成员函数的调用则是以类对象来修饰,提供一个隐含的this指针做参数,指向类对象。当然,类为类成员函数提供了一个命名空间。
从下面汇编代码可见,两者没有太大的区别:19:structCRectcr;20:cr。lenth0x20;004015D8movdwordptr〔ebp8〕,20h21:cr。width0x10;004015DFmovdwordptr〔ebp4〕,10h22:intararea(cr);004015E6leaeax,〔ebp8〕全局函数参数地址放到寄存器004015E9pusheax004015EAcallILT650(area)(0040128f)全局函数调用004015EFaddesp,4004015F2movdwordptr〔ebp0Ch〕,eax23:returnar;004015F5moveax,dwordptr〔ebp0Ch〕24:}42:CppRectcr;43:cr。lenth0x20;00401678movdwordptr〔ebp8〕,20h44:cr。width0x10;0040167Fmovdwordptr〔ebp4〕,10h45:intarcr。area();00401686leaecx,〔ebp8〕成员函数this指针放到寄存器00401689callILT75(CppRect::area)(00401050)成员函数调用0040168Emovdwordptr〔ebp0Ch〕,eax46:returnar;00401691moveax,dwordptr〔ebp0Ch〕47:}
如果结构体变量或类对象定义在全局区,汇编后,其实也看不到什么对象的影子了:49:structCRectgrect;50:voidtest(){004016E0pushebp004016E1movebp,esp004016E3subesp,40h004016E6pushebx004016E7pushesi004016E8pushedi004016E9leaedi,〔ebp40h〕004016ECmovecx,10h004016F1moveax,0CCCCCCCCh004016F6repstosdwordptr〔edi〕51:grect。length0x20;004016F8movdwordptr〔grect(0047cde8)〕,20h全局区结构体数据成员赋值52:grect。width0x10;00401702movdwordptr〔grect4(0047cdec)〕,10h53:printf(usingstructtodefileagloble:d,area(grect));0040170Cpushoffsetgrect(0047cde8)00401711callILT660(area)(00401299)00401716addesp,400401719pusheax0040171Apushoffsetstringusingstructtodefileagloble:。。。(0046f01c)0040171Fcallprintf(00420860)00401724addesp,854:}56:CppRectgcppRect;57:voidtest2(){00401750pushebp00401751movebp,esp00401753subesp,40h00401756pushebx00401757pushesi00401758pushedi00401759leaedi,〔ebp40h〕0040175Cmovecx,10h00401761moveax,0CCCCCCCCh00401766repstosdwordptr〔edi〕58:gcppRect。length0x20;00401768movdwordptr〔gcppRect(0047cdf0)〕,20h全局区对象数据成员赋值59:gcppRect。width0x10;00401772movdwordptr〔gcppRect4(0047cdf4)〕,10h60:printf(usingclasstodefileagloble:d,gcppRect。area());0040177Cmovecx,offsetgcppRect(0047cdf0)00401781callILT75(CppRect::area)(00401050)00401786pusheax00401787pushoffsetstringusingclasstodefileagloble:。。。(0046f048)0040178Ccallprintf(00420860)00401791addesp,861:}004017A6int3
以下代码可见类对象相对于类成员的基地址及命名空间功能:includeiostreamusingnamespacestd;classPerson{public:intmid;intmage;intmheight;voiddisplay(){类名给成员函数提供了一个命名空间coutmid,mage,mheightendl;}};voidtest(){Personperson;person。mid10;person。mage20;person。mheight30;person。display();Personp(Person)person。mage;p提供了一个新的偏移基准pmid40;此处的成员只提供基于p到mid的偏移:psizeof(int)2pmage50;此处的成员只提供基于p到mid的偏移:psizeof(int)3coutperson。mid,person。mage,person。mheightendl;person。display();pdisplay();编译器通过类对象名给函数提供了一个隐含的this指针参数this指针等于p的值,其成员变量的地址是相对于p处的偏移}voiddisplay(){并没有命名冲突;}voidtest2(){不使用实例来也可以调用成员函数couttest2:;Personperson;person。mid10;person。mage20;person。mheight30;typedefvoid(funcP)();funcPfpNULL;void(Person::fpp)()Person::display;成员函数指针memcpy(fp,fpp,sizeof(fpp));asmleaecx,person;x86编译器将this指针存放在寄存器ecx中fp();不通过实例person间接调用Person::diaplay()(person。fpp)();通过函数指针调用Person::diaplay()}intmain(){test();test2();while(1);return0;}10,20,3010,40,5010,40,5040,50,1245000
从以上可知,通过对象指针访问数据成员时,数据成员名提供的是一个相对于基地址的偏移的功能。成员函数定义时,类名给成员函数提供了一个命名空间,类对象调用成员函数时,编译器通过类对象名给函数提供了一个隐含的this指针参数。
End
新品揭幕丨隆崎SCARA机器人KLS400KLS600(ChinaIT。com讯)科技发展是3C、家电、医疗等多个行业发展的重要驱动力,随着各行业不断向智能化方向发展,对产品精细程度的要求也在不断提高,这就促使相关生产设备需要完成……
如何定义SaaS企业活跃度指标?众所周知,客户成功经理(CSM)工作中最关注的几个指标是:客户数续约率金额续费率(含增购)产品使用活跃率NPS(净推荐值)其它指标都是滞后的,而活跃率是最及时的指标;能看……
一加8T曝光了哪些信息?所有官方消息及解读都在这儿即将于10月15日发布的一加8T新品,官方最先确认的消息自然是发布会时间。这一时间点相比于往期产品,算是基本相当范围,但若是从今年上半年一加8系列新品提前一个月的发布节奏来看,……
液晶拼接屏的四种安装方式近些年,由于液晶显示技术在经过了不断了研究和实验后,变得越来越成熟,促使出现在市面上的液晶显示产品也越来越多。液晶拼接屏正是其中之一,在我们的日常生活和工作当中经常都可以看到它……
哈弗XY定名神兽,百兽之王能否成爆款?在看惯了哈弗以动物命名之后,这次哈弗带来了一款百兽之王,名字叫哈弗神兽。可以看出这次哈弗真的发威了,不是大狗、赤兔了。扉旅汽车小编从哈弗品牌官方获悉,哈弗神兽正是此前在上……
基层专业音响技术全解析之户外演出篇阜新声艺视听随着人们艺术欣赏水平的提高,基层的演出活动对音响的要求也越来越高。由于基层专业音响技术人员大都是半路出家,没有经过系统的学习,加上基层单位所购置的音响设备有限,以至于在演出过程……
创维汽车开启未来智能汽车新征程2021年4月27日,开沃新能源汽车集团在北京举办创维汽车品牌见面会,正式发布创维汽车品牌。开沃新能源汽车集团自成立以来,在新能源汽车领域深耕和布局十来年,已经形成了完备的研发……
消博会京东生活服务全员亮相昭示京质生活方式变革趋势5月7日至10日,首届中国国际消费品博览会在海南举行。京东组团参展,其中,生活服务事业群的6大业务悉数亮相,并与美孚、马牌、天际汽车、优信、海马体、特来电等多家来自汽车、本地生……
2020中国网络招聘市场发展研究报告核心摘要:发展环境政策方面:国家围绕稳就业原则,多方意见推进人才资源有效配置经济方面:服务业支撑带动作用不断增强,第三产业对GDP的贡献率也逐年上升,2019……
腾讯郭殿升GIS的使命是刻画世界理解世界创造世界近日,2020GIS软件技术大会在北京举行,汇聚众多行业领导、专家和企业共同参与,大会聚焦地理信息技术与区块链、大数据、人工智能等技术的融合创新,以及GIS软件最新进展、GIS……
苹果隐私新规,再立行业标杆苹果在隐私保护方面一直走在行业的前端,最近又搞出了一个可能影响整个数字经济和数字广告业的大动作。自本周一开始,苹果更新的隐私政策将正式生效,应用程序需要征求iPhone手……
粉转路Linksys已成为历史昔日的超神爆款,如今却仅剩空壳一直是Linksys的忠实用户,前段时间上头下单了Linksys的mx10600,最近app更新了方便点了,之前一塌糊涂,老房子网络线路都不通,想买个mesh走无线,但是确实真……