iOS联合体、位域

从 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.

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,254评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,875评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,682评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,896评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,015评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,152评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,208评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,962评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,388评论 1 304
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,700评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,867评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,551评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,186评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,901评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,142评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,689评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,757评论 2 351

推荐阅读更多精彩内容