做企业网站国内发展,wordpress首页文件代码在,加盟商,网站内容由什么组成部分面向对象的语言中#xff0c;类这种语言特性是最基本也是最重要的东西。这篇博客记录下从汇编角度去理解类的本质是什么。创建一个对象的本质又是什么。
一.C语言中的结构体和C的类有啥区别
我们知道在C语言中#xff0c;有语言本身自带的一些内置类型。比如int#xff0c…面向对象的语言中类这种语言特性是最基本也是最重要的东西。这篇博客记录下从汇编角度去理解类的本质是什么。创建一个对象的本质又是什么。
一.C语言中的结构体和C的类有啥区别
我们知道在C语言中有语言本身自带的一些内置类型。比如intchar,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去调试分析下
#includeiostream
#includestring
using namespace std;class Student {public:string name;int age;void ShowStudent(){coutname name age age endl;}};
int main(){Student s1;s1.nameChenWeiXin;s1.age2;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中好像不是这么做的。具体有待研究。我查资料说是虚函数是这么做的。到时候验证下。 以上就是我自己对类的一个理解。如果有错误欢迎评论指出。感激不尽。