范文健康探索娱乐情感热点
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文

C从汇编代码角度理解类和对象提供的命名空间地址偏移

  假设对某一个小问题的代码有两个写法A,B,其中A使用较简单的语法,需要写较多的代码;B使用较抽象的语法,只需要写较少的代码。B使用的语法是对A使用的语法的抽象,称为语法糖,其中的对应关系由编译器来实现,如:int arr[5] = {1,2,3}; arr[2] = 33;  *(arr+2) = 33;  // 可以理解为前一种写法是后一种写法的语法糖
  我们知道,从机器语言到汇编语言到高级语言,实现了逐层抽象,中间的翻译工作由翻译程序汇编器和编译器来实现。高层抽象可以理解为低层抽象的语法糖。
  一定程度上,面向对象可以理解为面向过程的语法糖,或者说,两者只是组织代码的方式发生了变化而已,数据可以聚合到结构体或类,而函数以结构体为参数,或函数隐含一个this指针做参数,指向类对象(当然,这里是就抽象和封装而言,类还提供更多的功能,如RAII,继承,多态,RTTI等):#include  using namespace std;  // 角色c1 长方形接口定义者,可放到头文件,使用文件来区分模块 struct CRect{     int lenth;     int width; }; int area(struct CRect *cr);  // 角色c2 长方形接口实现者,可以放到实现文件 int area(struct CRect *cr){     return cr->lenth * cr->width; }  // 角色c3 长方形接口使用者,可以放到使用文件 int calc() {     struct CRect cr;     cr.lenth = 0x20;     cr.width = 0x10;     int ar = area(&cr);     return ar; }  // 角色cpp1 长方形接口定义者,可放到头文件,使用文件和类来区分模块 class CppRect{ public:     int lenth;     int width;     int area(); };  // 角色cpp2 长方形接口实现者,可以放到实现文件 int CppRect::area(){     return lenth * width; }  // 角色cpp3 长方形接口使用者,可以放到使用文件 int calc2() {     CppRect cr;     cr.lenth = 0x20;     cr.width = 0x10;     int ar = cr.area();     return ar; }  int main() {     printf("using struct: rect"s area is %d ", calc());     printf("using class: rect"s area is %d ", calc2());     while(1);     return 0; } /* using struct: rect"s area is 512 using class: rect"s area is 512 */
  从以上实例可见,数据的聚合没有区别,都是由结构体变量或类对象提供一个基地址,而数据成员提供一个相对于基地址的偏移。处理结构体的全局函数以结构体变量或指针为参数,而类的成员函数的调用则是以类对象来修饰,提供一个隐含的this指针做参数,指向类对象。当然,类为类成员函数提供了一个命名空间。
  从下面汇编代码可见,两者没有太大的区别:19:       struct CRect cr; 20:       cr.lenth = 0x20; 004015D8   mov         dword ptr [ebp-8],20h 21:       cr.width = 0x10; 004015DF   mov         dword ptr [ebp-4],10h 22:       int ar = area(&cr); 004015E6   lea         eax,[ebp-8] // 全局函数参数地址放到寄存器 004015E9   push        eax     004015EA   call        @ILT+650(area) (0040128f)  // 全局函数调用 004015EF   add         esp,4 004015F2   mov         dword ptr [ebp-0Ch],eax 23:       return ar; 004015F5   mov         eax,dword ptr [ebp-0Ch] 24:   }  42:       CppRect cr; 43:       cr.lenth = 0x20; 00401678   mov         dword ptr [ebp-8],20h 44:       cr.width = 0x10; 0040167F   mov         dword ptr [ebp-4],10h 45:       int ar = cr.area(); 00401686   lea         ecx,[ebp-8]  // 成员函数this指针放到寄存器 00401689   call        @ILT+75(CppRect::area) (00401050) // 成员函数调用 0040168E   mov         dword ptr [ebp-0Ch],eax 46:       return ar; 00401691   mov         eax,dword ptr [ebp-0Ch] 47:   }
  如果结构体变量或类对象定义在全局区,汇编后,其实也看不到什么对象的影子了:49:   struct CRect g_rect; 50:   void test(){ 004016E0   push        ebp 004016E1   mov         ebp,esp 004016E3   sub         esp,40h 004016E6   push        ebx 004016E7   push        esi 004016E8   push        edi 004016E9   lea         edi,[ebp-40h] 004016EC   mov         ecx,10h 004016F1   mov         eax,0CCCCCCCCh 004016F6   rep stos    dword ptr [edi] 51:       g_rect.length = 0x20; 004016F8   mov         dword ptr [g_rect (0047cde8)],20h  // 全局区结构体数据成员赋值 52:       g_rect.width = 0x10; 00401702   mov         dword ptr [g_rect+4 (0047cdec)],10h 53:       printf("using struct to defile a globle:%d ",area(&g_rect)); 0040170C   push        offset g_rect (0047cde8) 00401711   call        @ILT+660(area) (00401299) 00401716   add         esp,4 00401719   push        eax 0040171A   push        offset string "using struct to defile a globle:"... (0046f01c) 0040171F   call        printf (00420860) 00401724   add         esp,8 54:   } // ……  56:   CppRect g_cppRect; 57:   void test2(){ 00401750   push        ebp 00401751   mov         ebp,esp 00401753   sub         esp,40h 00401756   push        ebx 00401757   push        esi 00401758   push        edi 00401759   lea         edi,[ebp-40h] 0040175C   mov         ecx,10h 00401761   mov         eax,0CCCCCCCCh 00401766   rep stos    dword ptr [edi] 58:       g_cppRect.length = 0x20; 00401768   mov         dword ptr [g_cppRect (0047cdf0)],20h // 全局区对象数据成员赋值 59:       g_cppRect.width = 0x10; 00401772   mov         dword ptr [g_cppRect+4 (0047cdf4)],10h 60:       printf("using class to defile a globle:%d ",g_cppRect.area()); 0040177C   mov         ecx,offset g_cppRect (0047cdf0) 00401781   call        @ILT+75(CppRect::area) (00401050) 00401786   push        eax 00401787   push        offset string "using class to defile a globle:%"... (0046f048) 0040178C   call        printf (00420860) 00401791   add         esp,8 61:   } 004017A6   int         3
  以下代码可见类对象相对于类成员的基地址及命名空间功能:#include  using namespace std;  class Person{ public:     int m_id;     int m_age;     int m_height;     void display(){  //类名给成员函数提供了一个命名空间         cout<m_id = 40; // 此处的成员只提供基于p到m_id的偏移:p+sizeof(int)*2     p->m_age = 50;// 此处的成员只提供基于p到m_id的偏移:p+sizeof(int)*3     cout<display(); // 编译器通过类对象名给函数提供了一个隐含的this指针参数     // this指针等于p的值,其成员变量的地址是相对于p处的偏移 }  void display(){  // 并没有命名冲突     ; }  void test2(){  // 不使用实例来也可以调用成员函数     cout<<"test2: ";     Person person;     person.m_id = 10;     person.m_age = 20;     person.m_height = 30;     typedef void (*funcP)();     funcP fp = NULL;     void (Person::*fpp)() = &Person::display; // 成员函数指针     memcpy(&fp,&fpp,sizeof(fpp));     __asm lea ecx, person; // x86编译器将this指针存放在寄存器ecx中     fp();               // 不通过实例person间接调用Person::diaplay()     (person.*fpp)();    // 通过函数指针调用Person::diaplay() }  int main() {          test();     test2();     while(1);     return 0; } /* 10,20,30 10,40,50 10,40,50 40,50,1245000 */
  从以上可知,通过对象指针访问数据成员时,数据成员名提供的是一个相对于基地址的偏移的功能。成员函数定义时,类名给成员函数提供了一个命名空间,类对象调用成员函数时,编译器通过类对象名给函数提供了一个隐含的this指针参数。
  -End-

依然是性价比小米再次拉低智能手表门槛现在热门的智能产品除了智能音箱感觉就是智能手表了,当年智能手环火爆的时候也有入手,虽然性价比高,但是屏幕小功能少也限制手环的市场。智能手表功能全可玩性高,缺点就是价格略高,基本上都OPPOReno7标准版竟使用金属中框,OPPO良心发现?刚发布的OPPOReno7系列有三款,分别为OPPORenoSE,OPPOReno7和OPPOReno7Pro。毫无疑问,其中OPPOReno7就是标准版的定位了。不过这一次令我意4K电竞显示器正确打开方式,极致光线追踪,少不了旗舰卡RTX3090前言初中时候,在广州儿童公园看到有大神用60寸以上的大屏幕玩街机游戏。虽说是1991年那种像素块的游戏,不过超大屏幕的带来的震撼感还是让几乎全公园的人都停步。相信游戏玩家都有一个梦你认为最耐用国产手机是什么?最近几年,国产手机进步非常大,在质量和创新上与国际品牌三星苹果差距越来越小。特别是华为和小米,在某些方面甚至有超过三星苹果的趋势,因此越来越多的国人开始选择国产手机。所谓十年磨一剑液晶电视摔坏了怎么办?液晶显示器简称LCD(LiquidCrystalDisplay),采用一种介于固态和液态之间的物质,具有规则性分子排列的有机化合物,加热呈现透明状的液体状态,冷却后出现结晶颗粒的混有哪些是你们买完后悔的手机?1华为P10华为P10经过闪存门后的成为了一款被人们诟病的手机,也被称为一部坑人的手机。P10宣传了很久,造势很大,大家对P10的期待度也非常高,可从内存缩水屏幕没有疏油层到闪存门鸿蒙系统要想快速推广,提高市场占有率,你有啥好建议?我先来说一说,仅是抛砖引玉。我的手机是vivo,想抢华为nova8很久了,想着华为CPU配华为鸿蒙,哪是绝配,可是,抢了很多次都没有结果,可想而知,华为被人制裁有多憋屈。明明自己是小米汽车总部宣告落户北京经开区,整车工厂计划年产30万辆记者伍洋宇编辑11月27日,北京亦庄微信公众号发布消息,北京经济技术开发区管委会与小米科技进行签约,正式宣告小米汽车落户北京经开区。小米汽车项目更多细节释出。据悉,小米汽车总部基地北京开放自动驾驶出行商业化试点价格如何确定?来源北京日报手机下单,自动驾驶乘用车为您服务。25日,北京正式开放国内首个自动驾驶出行服务商业化试点,率先在经济技术开发区60平方公里范围投入不超过100辆自动驾驶车辆开展商业化服元宇宙的主力部队华为入局元宇宙了。在很多人纷纷打假的时候,诸多科技巨头正在紧锣密鼓的布局元宇宙。真有意思,很多人都不知道元宇宙是啥就先义愤填膺的去打假了,看来被梦想窒息之流坑怕了。这些年毕竟被各种36氪首发布局配药机器人,博为医疗完成数千万元A轮融资近日,36氪获悉,智慧医疗领域中智能化静脉药物调配系统研发公司博为医疗(全称为深圳市博为医疗机器人有限公司)完成数千万元A轮融资,由某战略投资方投资。此前,公司曾获天使轮和A轮融资
S21销量惨败,Note新机被砍,三星还是安卓机皇吗?在刚过去不久的6月份里,小米首次在智能手机市场上超越了三星和苹果,以17。1的份额占比拿下全球第一称号,这是继华为之后第二个将三星挤下神坛的手机厂商,这足以证明三星手机目前发展情况陌陌更名Hello,不惜撞名也要塑造新印象8月2日,陌陌宣布公司法定名称从MomoInc。更改为HelloGroupInc。。从陌陌更名到Hello集团,整体变更为集团化运营。从微信摇一摇到专业的陌生人社交软件,对于在互联为什么P2P的暴雷是必然的?网贷平台又是如何运作的呢?为什么说P2P的暴雷是必然的呢?好的知识改变你的认知,大家好,我是墨冰寒雪,今天我们就来聊一聊令人憎恶的P2P,什么是P2P呢?P2P就是网贷机构,在2018年的时候,国家出台了相前期引流后期培训,职业教育机构如何发挥直播最大价值?疫情反复,线下场景受限,不少企业选择转战线上市场,将直播作为连接线上和线下市场的桥梁,开启OMO运营新模式。尤其职业教育,伴随着政策扶持资本入局等一系列利好因素刺激,发展进入快车道字节教育转型GOGOKID将被放弃京东零售宣布新一轮高管任命据晚点LatePost报道,字节跳动旗下教育品牌大力教育正在进行新一轮调整向38岁孩子提供AI动画课程的瓜瓜龙开始裁撤辅导老师,计划在8月底前裁撤50以上的体验课辅导老师向312岁网易云可以听周杰伦的歌了!腾讯被罚网络音乐独家版权终于到头了腾讯终于为责令解除网络音乐的独家版权了,这是不是意味着咱们在QQ系以外的平台也可以听到周杰伦的歌了呢?非常有可能,但很多人想不通啊,他们没有了独家版权,我是不是得到处开会员啊?这么服务,才是实体零售的杀手锏出品联商专栏撰文张菲霏叶雯洁当下所有的实体零售人都在哀叹生意是越来越难做了!在分析生意难做的原因时,不约而同地把矛头指向了电商,认为都是电商惹的祸。另一方面,大家也认为实体店的优势乐视怒撕爱奇艺!以盗播为由成功索赔28万,网友终于出息了资本上捉襟见肘,是乐视一直以来的硬伤。仿佛贾跃亭开创了乐视,是给自己挖了一个金钱黑洞。但这次,在被执行总金额超20。19亿元之后,乐视终于赚钱了!有网友调侃道乐视啊,你终于出息一回腾讯音乐支付宝均跑步入场,NFT会让艺术人赚得盆满钵满吗?文张毅7月24日,国家监督总局刚刚责令腾讯音乐(TME)解除独家版权7月30日,腾讯音乐就宣布计划在8月推出NFT加密艺术品平台服务TME数字藏品。艺术与NFT再一次走在了一起。大辽宁省5G电话用户超千万移动互联网流量大幅增长全省5G电话用户突破1千万6月户均移动互联网接入流量增速排名全国首位(沈阳日报沈报全媒体高级记者刘洋)8月6日,记者从辽宁省通信管理局获悉,截至2021年6月末,辽宁省5G电话用户论阿里网络水军的可怕一个女子被公司领导强奸了4次,她第一时间已经报警了,报警无果再找公司寻求帮助的。诺大的阿里巴巴,想进去的人,肯定是相信阿里巴巴的公平公正的,但是阿里公司却想着息事凌人,就把事情压下