对象的创建核心有三步:
-
cls->instanceSize
:计算需要开辟的内存空间大小 -
calloc
:申请内存,返回地址指针 -
obj->initInstanceIsa
:将 类 与 isa 关联
具体讲解可见前两篇文章:
一、alloc & init底层探索
二、内存对齐原则及OC对象内存
接下来将对isa
和isa关联类
进行解析, 在讲解之前先了解下结构体(Struct)
、联合体(Union)
和位域
, 下篇进入isa与类关联四、isa与类关联的原理
结构体(Struct)
结构体是C语言中一种重要的数据类型,该数据类型由一组称为成员(或称为域,或称为元素)的不同数据组成,其中每个成员可以具有不同的类型。结构体通常用来表示类型不同但是又相关的若干数据。
结构体类型不是由系统定义好的,而是需要程序设计者自己定义的。C语言提供了关键字struct
来标识所定义的结构体类型。
关键字struct
和结构体名
组合成一种类型标识符,其地位如同通常的int
、char
等类型标识符,其用途就像 int 类型标识符标识整型变量一样可以用来定义结构体变量。定义变量以后,该变量就可以像定义的其他变量一样使用了;
成员
又称为成员变量
,它是结构体所包含的若干个基本的结构类型,必须用“{}”括起来,并且要以分号结束,每个成员应表明具体的数据类型。
struct LGStruct1 {
double a; // 8 (0-7)
char b; // 1 [8 1] (8)
int c; // 4 [9 4] 9 10 11 (12 13 14 15)
short d; // 2 [16 2] (16 17)
}struct1;
内存使用符合内存对齐原则
联合体/共用体(Union)
联合体(union)
与结构体(struct)
有一些相似之处。但两者有本质上的不同
。在结构体
中,各成员有各自的内存空间
, 一个结构变量的总长度是各成员长度之和
。而在联合体
中,各成员共享
一段内存空间
, 一个联合变量
的长度等于各成员中最长的长度
。
联合体是一个结构
- 它的所有成员相对于基地址的偏移量都为0;
- 此结构空间要大到足够容纳最"宽"的成员;
- 其对齐方式要适合其中所有的成员;
联合体的内存对齐
联合体所占空间需要满足的条件:
- 大小足够容纳最宽的成员;
- 大小能被其包含的所有
基本数据类型
的大小所整除。
union U
{
char s[9]; // 9
int n; // 4
double d; // 8
};
复制代码联合体的大小为 16。
位域
位域定义与结构定义相仿,其形式为:
struct 位域结构名
{
位域列表
};
其中位域列表的形式为:
类型说明符 位域名: 位域长度(占多少位)
例如:
struct bs{
int a:8;
int b:2;
int c:6;
}data;
说明 data 为 bs 变量,共占两个字节。其中位域 a 占 8 位,位域 b 占 2 位,位域 c 占 6 位。
对于位域的定义尚有以下几点说明:
int : 0表示下面出现的类型不能够再往里面填充。
struct area
{
int a:3;
int:0; //告诉下面,20不能够放到a的那块存储区域去了
int c:20;
};
结构体大小为4+4=8;如果没有int:0,大小为4。
int : x 表示占用几个位,占用部分不可用,但是接下来的位可继续往上面填充。
struct area
{
int a:3;
int:4; //表示a和c中间有4位不可用。
int c:20;
};
该结构体大小为4。
如果int:4改为int:10,那么该结构体大小会变为8。
位域不能跨字节,位域需要跟结构体最长类型对齐,前面的类型应自动对齐,然后再进行填充。
struct area1
{
char a:6; //向int对齐,扩展为32位
char b:3;
int c:22;
};
结构体大小 :8
struct area2
{
char a:6; //向int对齐,扩展为32位
char b:3;
int c:21;
};
结构体大小 :4
位域压缩规则
- 如果相邻位域字段的类型相同,且其位宽之和小于这个类型的sizeof大小,则后面的字段将紧邻前一个字段存储,直到不能容纳为止;
- 如果相邻位域字段的类型相同,但其位宽之和大于类型的sizeof大小,则后面的字段将从新的存储单元开始,其偏移量为其类型大小的整数倍;
- 如果相邻的位域字段的类型不同,则各编译器的具体实现有差异,VC6采取不压缩方式,Dev-C++采取压缩方式;
- 如果位域字段之间穿插着非位域字段,则不进行压缩;
- 整个结构体的总大小为最宽基本类型成员大小的整数倍。