三、结构体(Struct)/联合体(Union)/位域

对象的创建核心有三步:

  • cls->instanceSize:计算需要开辟的内存空间大小
  • calloc:申请内存,返回地址指针
  • obj->initInstanceIsa:将 类 与 isa 关联
    具体讲解可见前两篇文章:
    一、alloc & init底层探索
    二、内存对齐原则及OC对象内存

接下来将对isaisa关联类进行解析, 在讲解之前先了解下结构体(Struct)联合体(Union)位域, 下篇进入isa与类关联四、isa与类关联的原理

结构体(Struct)

结构体是C语言中一种重要的数据类型,该数据类型由一组称为成员(或称为域,或称为元素)的不同数据组成,其中每个成员可以具有不同的类型。结构体通常用来表示类型不同但是又相关的若干数据。

结构体类型不是由系统定义好的,而是需要程序设计者自己定义的。C语言提供了关键字struct来标识所定义的结构体类型。

关键字struct结构体名组合成一种类型标识符,其地位如同通常的intchar等类型标识符,其用途就像 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++采取压缩方式;
  • 如果位域字段之间穿插着非位域字段,则不进行压缩;
  • 整个结构体的总大小为最宽基本类型成员大小的整数倍。

你可能感兴趣的:(三、结构体(Struct)/联合体(Union)/位域)