逆向分析C++类的本质

面向对象的语言中,类这种语言特性是最基本也是最重要的东西。这篇博客记录下从汇编角度去理解类的本质是什么。创建一个对象的本质又是什么。

一.C语言中的结构体和C++的类有啥区别

我们知道在C语言中,有语言本身自带的一些内置类型。比如int,char,float等等。这些都是C语言编译器做好规划的,比如说我现在创建一个int类型的变量,那么编译器就会在为我们分配一个4字节的内存大小,并标识这块内存是整形变量。其实创建变量的本质就是在内存开辟适当大小的空间供数据存放。那么问题就来了,内置类型都是事先做好设定的。并不能满足用户的多样性数据存储。因此C语言就有了用户自定义类型-struct结构体。结构体的本质就是能让用户创建自定义的各种变量的集合体以此来满足用户对数据存储和管理的一种办法。比如我现在想创建如下结构体:

    struct Stduent {char name[10];int age;int Class_num;};

那么本质就是在内存中会创建一个如图的内存:


因此这就是为什么在计算结构体的大小的时候,是按照每个类型的大小相加的总共。讲明白了这个接下来就是讲C++的类。C++的类跟C语言中的结构体本质上是一个东西。但是他会多一点东西。下面分点讲解:

1.C语言中,结构体中只有属性也就是数据类型,没有函数也不能定义函数,而在C++中类中是可以定义方法的(也就是函数)。

2.C语言中,结构体中权限默认是public类型的,而C++中类的权限默认是private。

3.C语言中,创建一个结构体仅仅只是开辟了一块存放结构体大小的内存,而在C++中,创建一个对象会自动调用构造函数,释放的时候会自动调用析构函数。

以上就是C的结构体和C++类的基本区别和相似点。

结构体跟类一样,在没初始化的时候,都类似于模板,存在于数据区。本质是告诉编译器有这么个模板,用户需要创建的时候,根据这个模板来创建。因此我们的结构体和类如果被创建会有两个地方存储,一个是栈,一个就是堆,取决于你的创建方式。如果是在函数内部初始化那么相当于局部变量,是在栈上布局的。如果是采用malloc或者new,那么这些结构体和类的初始化数据将会布局在堆上。这是一个很重要的点。


二.C++逆向分析类

既然C结构体和类本质上是一个东西,那么它在内存是怎么布局的呢?我们写一个小的demo去调试分析下:

#include<iostream>
#include<string>
using namespace std;class Student {public:string name;int age;void  ShowStudent(){cout<<"name="<< name <<   "age= "<< age <<endl;}};
int main(){Student s1;s1.name="ChenWeiXin";s1.age=2;s1.ShowStudent();return 0;}

上面我们讲了,C++的类中不仅有属性,还有方法。一般我们称之为成员属性,成员方法。其实就是数据类型和函数的组合体。

现在我们逆向分析对象的创建过程和变量赋值,成员方法调用和对象销毁的过程。这里我是用g++编译的,不同的编译器编译出来的效果和特性都是不一样的,主要区别是一些细节上的问题。


我们看到当我们即将创建一个对象的时候,他会有三步操作。

1.lea rax,[rbp-0x40]   //取rbp-0x40的地址赋值给rax

2.mov rdi,rax       //将rax的值赋值给rdi

3.call Student:Student()      //调用Student对象的构造函数


首先我们要知道一件事情,就是Linux上的x64函数调用规则,顺序是rdi,rsi,rdx,rcx,r8,r9--栈。

也就是说如果参数低于6个用寄存器传参,高于6个会在栈上。正向学C++的时候,我们知道,在调用成员函数的时候,默认第一个参数其实是this指针。那么此时的rdi就是this指针,因为我们的源程序中没有自定义的构造函数,因此此时调用的是默认构造函数,没有其他参数,所以只要一个this指针参数。那么this指针是啥呢?其实它本质就是对象的首地址。[rbp-0x40]这个地址就是栈地址所以我们可以看到在main函数这个作用域中,s1对象在栈上布局的。

      

我们接着往下看:


此时我们跟着进来了这个构造函数,简单看下默认构造函数干了什么事情。好像啥也没干其实,调用了一个函数我也不知道干啥的,看上去是初始化一些啥的反汇编看了下:


大概猜测是跟字符串类的有关。

紧接着就来到了我们的对成员属性赋值的操作:


这里又干了什么呢,我们看到还是会将对象的首地址也即是this指针当第一个参数传递,第二个参数传的是rsi。盲猜是我们的字符串的地址。因为接下来调用的这个函数就是C++对字符串做赋值操作的一个函数:


数值赋值就相当简单:

因此我们明白了,对象的首地址在rbp-0x40的位置,也就是name的位置,rbp-0x20的位置存放的是我们的age。


这个age这里我不知道为啥还有0x55500000的存在。但是这个确实就是age字段,而且里面有些奇奇怪怪的东西,我也搞不懂(研究了比较久age字段后面这个奇怪的数字)不过大致布局我们是清晰的。


这里我猜测是为了8字节对齐。这样数据读取更快。紧接着我们又看到调用了成员方法:


还是老规矩,传入this指针,然后call我们的ShowStudent函数。具体我就不跟进去了。最后程序即将结束的时候:


依然是传入this指针,然后调用析构函数。这里的析构函数依然是默认的,因此也是啥也没干其实。

整个程序就走完了。通过上述分析,我们验证了如下几点:

1.对象的创建和销毁的时候,会自动调用构造函数和析构函数,即使不提供也会调用默认的。如果用户提供将会调用提供好的。

2.对象创建后对象中的成员属性如果是在函数中做为局部变量将会创建在栈上,如果用new创建将会在堆上。生命周期是不一样的。(堆上可以自行验证)

3.对象中的成员方法在单独的代码区。我一开始以为是会将成员方法的起始地址存放在属性字段的后面,但是好像不是那么回事。(我学java的时候记得是这么说的)。但是C++中好像不是这么做的。具体有待研究。我查资料说是虚函数是这么做的。到时候验证下。

以上就是我自己对类的一个理解。如果有错误欢迎评论指出。感激不尽。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/636197.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

kafka(一)——简介

简介 Kafka 是一种分布式、支持分区、多副本的消息中间件&#xff0c;支持发布-订阅模式&#xff0c;多用于实时处理大量数据缓存的场景&#xff0c;类似于一个“缓存池”。 架构 Producer&#xff1a;消息生产者&#xff1b;Consumer&#xff1a;消息消费者&#xff1b;Brok…

SpringCloud之Nacos的学习、快速上手

1、什么是Nacos Nacos是阿里的一个开源产品&#xff0c;是针对微服务架构中的服务发现、配置管理、服务治理的综合型解决方案&#xff0c;用来实现配置中心和服务注册中心。 Nacos 快速开始 2、安装运行nacos nacos下载地址 下载地址: https://github.com/alibaba/nacos/rel…

【Linux】Linux系统的生态

Linux中安装软件 Linux中安装软件一般有三种方式&#xff1a; 源代码安装rpm包安装yum安装 1.源代码安装 有些软件本来就是开源的&#xff0c;如果不想用别人直接发布好的软件&#xff0c;我们就可以把源代码下载下来&#xff0c;在我们的环境中编译&#xff0c;自己安装 …

防伪技术行业研究:年复合增长率约为10%

近年来&#xff0c;我国各种新的防伪技术不断涌现&#xff0c;部分防伪技术已经达到国际先进水平&#xff0c;并广泛应用于产品防伪、票证防伪等领域&#xff0c;推动了防伪行业的持续、健康发展。 常见的产品防伪技术有&#xff1a;隐形分子技术、二维码防伪、揭开留底防伪、安…

【设计模式 创建型】单例模式

类的单例设计模式&#xff0c;就是采取一定的方法保证在整个的软件系统中&#xff0c;对某个类只能存在一个对象实例&#xff0c;并且该类只提供一个取得其对象实例的方法&#xff08;静态方法&#xff09; 指一个类只有一个实例&#xff0c;且该类能自行创建这个实例的一种模…

「Kafka」Broker篇

「Kafka」Broker篇 主要讲解的是在 Kafka 中是怎么存储数据的&#xff0c;以及 Kafka 和 Zookeeper 之间如何进行数据沟通的。 Kafka Broker 总体工作流程 Zookeeper 存储的 Kafka 信息 启动 Zookeeper 客户端&#xff1a; [atguiguhadoop102 zookeeper-3.5.7]$ bin/zkCli.sh通…

时间复杂度的排序

在计算机科学中&#xff0c;不同的算法有不同的时间复杂度。以下是一些常见的时间复杂度&#xff0c;并按照它们的增长速度从低到高排序&#xff1a; O(1) - 常数时间复杂度&#xff1a; 表示算法的执行时间是固定的&#xff0c;不随输入规模的增加而变化。例如&#xff0c;直接…

使用 Docker 部署 的WAF: 雷池社区版

Web应用防火墙&#xff08;WAF&#xff09;是保护网站不受恶意攻击的关键组件。 使用 Docker 部署雷池社区版&#xff0c;可以大大简化安全管理工作。 一、WAF 雷池社区版简介 雷池社区版是一种流行的开源 Web 应用防火墙&#xff0c;它提供基本的安全保护&#xff0c;如防止…

多维表格产品vika多维表、Flowus、Wolai体验记录

昨天从下午6点肝到凌晨2点多体验低代码平台多维表格产品&#xff0c;体验了3个国内产品&#xff0c;vika多维表、Flowus、Wolai。 具有多维表格新型关系数据库的鼻祖是 Airtable&#xff0c;国内模仿产品有vika多维表、飞书多维表格等。 还有一种类型就是以在国内鼎鼎大名的N…

细讲Labview条件结构用法及易错点

本文讲解Labview条件结构的常用情景及易错点注意事项。帮助大家深刻理解并使用该结构&#xff0c;欢迎点赞关注加评论&#xff0c;有问题可以私聊或在下方评论区留言。 本文程序均附在文章结尾&#xff0c;可自行下载学习。 博主之前讲过Labview事件结构、For循环等的基础知识介…

每日OJ题_算法_滑动窗口⑥_力扣438. 找到字符串中所有字母异位词

目录 力扣438. 找到字符串中所有字母异位词 解析及代码1 解析及代码2 力扣438. 找到字符串中所有字母异位词 438. 找到字符串中所有字母异位词 - 力扣&#xff08;LeetCode&#xff09; 难度 中等 给定两个字符串 s 和 p&#xff0c;找到 s 中所有 p 的 异位词 的子串&am…

Mac Could not find the GDAL library 问题解决

目录 1. 参考2. 问题描述3. 解决步骤3.1. 安装依赖包3.2. 配置 GDAL_LIBRARY_PATH3.3. 配置 GEOS_LIBRARY_PATH 1. 参考 https://docs.djangoproject.com/en/5.0/ref/contrib/gis/install/#macos 2. 问题描述 苹果系统 Mac 中搭建 GeoDjango 开发环境时出现以下报错&#xf…

第十四章 MyBatis

第十四章 MyBatis 1.入门-课程介绍2.入门-快速入门程序3.配置SQL提示4.入门-JDBC5.入门-数据库连接池6.入门-lombok工具包介绍7.基础操作-环境准备8.基础操作-删除9.基础操作-删除&#xff08;预编译SQL&#xff09;10.基础操作-新增11.基础操作-新增&#xff08;主键返回&…

Python初识——小小爬虫

一、找到网页端url 打开浏览器&#xff0c;打开百度官方网页点击图片&#xff0c;打开百度图片 鼠标齿轮向下滑&#xff0c;点击宠物图片 进入宠物图片网页&#xff0c;在网页空白处点击鼠标右键&#xff0c;弹出的框中最下方显示“检查”选项&#xff0c;点击&#xff08;我是…

安全帽识别-赋能深圳自贸中心智慧工地

在当今的建筑行业中&#xff0c;安全管理一直是一个至关重要的议题。深圳自贸中心项目在这方面进行了一次有益的尝试——实施智慧工地安全帽识别系统。本文将对这一创新举措进行简要介绍。 项目背景 深圳自贸中心&#xff0c;作为一项标志性建设项目&#xff0c;承载着城市发展…

云的网络安全优势

在考虑迁移到云计算时&#xff0c;网络安全已经成为一个关键因素。毫无疑问&#xff0c;企业希望通过网络浏览器或移动应用为员工、合作伙伴和客户提供一致的数据和应用访问权限&#xff0c;以保持竞争力。 网络攻击的性质和重要性正变得越来越复杂&#xff0c;并造成严重的财…

【ASP.NET Core 基础知识】--路由和请求处理--Attribute路由

一、介绍 在ASP.NET Core中&#xff0c;路由是将传入的URL请求映射到正确的控制器和操作的方法。Attribute路由是一种基于属性&#xff0c;用于定义路由规则的方式&#xff0c;通过在控制器类和操作方法上应用特定的属性&#xff0c;来定义URL模板。 基本概念&#xff1a; **路…

线性代数逆矩阵的求法

在线性代数中&#xff0c;逆矩阵是一个非常重要且有趣的概念。一个 n 阶方阵 A 的逆矩阵&#xff0c;记作 A^-1&#xff0c;是指存在另一个 n 阶方阵 B&#xff0c;使得 A 和 B 的乘积等于单位矩阵 E&#xff0c;即&#xff1a; A * B E 或者等价地&#xff1a; B * A E 这里…

uniapp技术积累

2024.01.19 1.textarea &#xff08;1&#xff09;默认文字样式设置 placeholder-style"color:rgba(0,0,0,0.7)" 2024.01.18 1.hbuilderx运行uniapp到ipad&#xff08;复用率低&#xff09; &#xff08;1&#xff09;电脑端&#xff1a;首先会有一个运行工具包&…

只用Mysql搞一个分布式锁

在web开发中&#xff0c;分布式的锁的应用场景甚多&#xff0c;我们可以通过分布式锁来进行一些仅依赖于数据库的事务很难直接保证原子性的操作&#xff0c;比如多种不同数据源的访问&#xff0c;网络通信等等。多数情况下我们会使用memcache的add, redis中在set中指定nx参数等…