美文网首页
iOS联合体、位域

iOS联合体、位域

作者: 奉灬孝 | 来源:发表于2020-11-10 11:08 被阅读0次

从 isa 底层结构引入联合体、位域

isa底层结构分析中我们简单的介绍过 isa 的底层数据结构

union isa_t {
    isa_t() { }
    isa_t(uintptr_t value) : bits(value) { }

    Class cls;
    uintptr_t bits;
#if defined(ISA_BITFIELD)
    struct {
        ISA_BITFIELD;  // defined in isa.h
    };
#endif
};

通过上述源码发现 isa_t 是一个 union(共用体/联合体),联合体意味着公用内存 , 也就是说 isa 其实总共还是占用 8 个字节内存 , 共 64 个二进制位 。
其中 ISA_BITFIELD(位域) 宏定义在不同架构下表示如下 :

# if __arm64__
#   define ISA_BITFIELD                                                      \
      uintptr_t nonpointer        : 1;                                       \
      uintptr_t has_assoc         : 1;                                       \
      uintptr_t has_cxx_dtor      : 1;                                       \
      uintptr_t shiftcls          : 33; /*MACH_VM_MAX_ADDRESS 0x1000000000*/ \
      uintptr_t magic             : 6;                                       \
      uintptr_t weakly_referenced : 1;                                       \
      uintptr_t deallocating      : 1;                                       \
      uintptr_t has_sidetable_rc  : 1;                                       \
      uintptr_t extra_rc          : 19
# elif __x86_64__
#   define ISA_BITFIELD                                                        \
      uintptr_t nonpointer        : 1;                                         \
      uintptr_t has_assoc         : 1;                                         \
      uintptr_t has_cxx_dtor      : 1;                                         \
      uintptr_t shiftcls          : 44; /*MACH_VM_MAX_ADDRESS 0x7fffffe00000*/ \
      uintptr_t magic             : 6;                                         \
      uintptr_t weakly_referenced : 1;                                         \
      uintptr_t deallocating      : 1;                                         \
      uintptr_t has_sidetable_rc  : 1;                                         \
      uintptr_t extra_rc          : 8
  • 由于联合体的特性 , cls , bits 以及 struct 都是 8 字节内存 , 也就是说他们在内存中是完全重叠的。
  • 实际上在 runtime中,任何对 struct 的操作和获取某些值,如 extra_rc ,实际上都是通过对 bits 做位运算实现的。
  • bitsstruct 的关系可以看做 : bits 向外提供了操作 struct 的接口,而 struct 本身则说明了 bits 中各个二进制位的定义。

接下来我们深入研究一下联合体、位域。

联合体

  • 结构体和共用体的区别在于:结构体的各个成员会占用不同的内存,互相之间没有影响;而共用体的所有成员占用同一段内存,修改一个成员会影响其余所有成员。
  • 结构体占用的内存大于等于所有成员占用的内存的总和(成员之间可能会存在缝隙),共用体占用的内存等于最长的成员占用的内存。共用体使用了内存覆盖技术,同一时刻只能保存一个成员的值,如果对新的成员赋值,就会把原来成员的值覆盖掉。
// 联合体
union {
    char bits;
    // 位域
    struct { // 0000 1111
        char front  : 1;
        char back   : 1;
        char left   : 1;
        char right  : 1;
    };
} _direction;
  1. 联合体中可以定义多个成员,联合体的大小由最大的成员大小决定
  2. 联合体的成员公用一个内存,一次只能使用一个成员
  3. 对某一个成员赋值,会覆盖其他成员的值
  4. 存储效率更高,可读性更强,可以提高代码的可读性,可以使用位运算提高数据的存储效率

位域

结构体中除了可以定义基本数据类型外,还可以使用位域来构建数据成员,也就是说某个数据成员可能只占用结构体中某几个bit位的存储空间。结构体中定义位域的目的主要是为了节省内存空间。假如某个结构体中有 8BOOL 类型的数据成员用来描述 8 种状态。那么我们需要定义 8BOOL 类型的数据成员,这样这个结构体实例就占用了 8 个字节的内存空间,而如果我们使用 位域 来定义的话则可以用一个字节的内存空间就可以表述出来。定义 位域 的格式如下:

struct  {
    // 位域名 : 位域长
    char front : 1;
    char back : 1; 
    char left : 1; 
    char right  : 1;
};
  1. 位结构中的成员可以定义为 unsigned , 也可定义为 signed 或者是 char, 但当成员长度为 1 时, 会被认为是 unsigned 类型。因为单个位不可能具有符号。
  2. 位结构中的成员不能使用数组和指针, 但位结构变量可以是数组和指针, 如果是指针, 其成员访问方式同结构指针。
  3. 位结构总长度(位数), 是各个位成员定义的位数之和(如果类型相同的话)
  4. 位结构成员可以与其它结构成员一起使用。
    • 由于位域不允许跨两个字节,因此位域的长度不能大于一个字节的长度,也就是说不能超过 8 位二进位。
    • 位域可以无位域名,这时它只用来作填充或调整位置。无名的位域是不能使用的。
    • 如果相邻位域字段的类型相同,且其位宽之和小于类型的 sizeof 大小,则后面的字段将紧邻前一个字段存储,直到不能容纳为止。
#include <stdio.h>

struct test {
    char a : 2;
    char b : 3;
    char c : 1;
};

struct test1 {
    char a : 2;
    char b : 3;
    char c : 7;
};

struct {
    short int a:2;
    int b:4;
    char c;
}test2;

struct {
    int a:2;
    int b:4;
    char c;
}test3;

struct {
    short s1:3;
    short s2:3;
    short s3:3;
}test4;

struct{
    char c1:3;
    char c2:2;
    char c3:2;
}test5;

struct test6
{
    int a:4;
    int b:3;
    char c;
};

int main(int argc, const char * argv[]) {
    // insert code here...
    
    printf("test长度:%d\ntest1长度:%d\ntest2长度:%d\ntest3长度:%d\ntest4长度:%d\ntest5长度:%d\ntest6长度:%d\n",sizeof(struct test),sizeof(struct test1),sizeof(test2),sizeof(test3),sizeof(test4),sizeof(test5),sizeof(struct test6));

    return 0;
}

控制台输出:
test长度:1
test1长度:2
test2长度:4
test3长度:4
test4长度:2
test5长度:1
test6长度:4
Program ended with exit code: 0

小测验:

32位环境下,给定结构体

Struct A
{
    Char t:4;

    Char k:4;

    Unsigned short i:8;

    Unsigned long m;
};

sizeof ( A ) =_____;

A. 6
B. 7
C. 8
D. 上述答案都不对

变量后面加 : 然后加数字表示位域,也就是说着代表按位来存放的,不是按字节,这是计算机为了节约空间的一种方式。char是一个字节(8个位),所以 t和k 加起来刚好8个位,也就是一个字节。然后short 一共16个位放了8个,剩下8个不够后面long存放,所以算两个字节。因为long在32是4个字节,所以一共 1 +2 +4 = 7 。然后进行结构体对齐,所以就是8.

相关文章

  • iOS联合体、位域

    从 isa 底层结构引入联合体、位域 在isa底层结构分析[https://www.jianshu.com/p/3...

  • Runtime源码剖析-对象

    Runtime源码剖析-对象 预备知识 如果大家对联合体、位域相关知识不够熟悉的话,请参考联合体+位域[https...

  • 联合体和位域

    联合体和位域 在上一篇iOS中关于内存对齐的探究[https://www.jianshu.com/p/c913b5...

  • iOS 知识补充: 联合体、位域

    文集:iOS 知识补充[https://www.jianshu.com/c/1422baa6495c] 前言 这篇...

  • 联合体&位域

    首先我们创建一个类,里面有三个BOOL类型属性 创建一个对象,打印内存大小 打印出来占16字节(isa:8,tal...

  • 隐藏在 OC 中的那些暗招 &位域&联合体&am

    如果没有听说过 isa_t,只是听说过 isa 指针,那么这篇简书值得一看。 一、位域与联合体 1.1 位域 位域...

  • iOS位运算及联合体位域

    1. 概述 今天来点概念性的东西,如果在代码中用到位运算和联合体位域,是不是会显得高级一些呢?哈哈。 作为一个开发...

  • 联合体与位域

    在对 OC 对象创建的探究过程中,我们发现一个很有趣的实现 isa。isa 是将对象内存空间与 class 之间联...

  • 联合体与位域

    联合体 定义 联合体也叫共用体,由不同的数据类型组成,其变量互斥,存储方式是所有成员共用一个段内存,共同体同一时刻...

  • iOS大师班笔记

    四、类的本质 联合体的互斥 isa的结构为联合体+位域的结构,以达到直接操作二进制位的目的,节约了内存。如果使用属...

网友评论

      本文标题:iOS联合体、位域

      本文链接:https://www.haomeiwen.com/subject/vorrbktx.html