美文网首页iOS 知识补充
iOS 知识补充: 联合体、位域

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

作者: 欧德尔丶胡 | 来源:发表于2020-09-10 21:05 被阅读0次

文集:iOS 知识补充

前言

  • 这篇主要内容记录 联合体 位域 的学习,用于在OC底层学习探索isa指针优化做下笔记,学习参考转载:孙优秀丶

  • 联合体 位域作用:让内存更加优化

1. 位域

@interface Person()
{
    struct  {
        // 位域名 : 位域长
        char tall : 1;// 是否高
        char rich : 1; // 是否有钱
        char humor : 1; // 是否幽默
    } myself;
    
    char _my;
}
@end
@implementation Person

-(void)setRich:(BOOL)rich{
    myself.rich = rich;

}
-(void)setTall:(BOOL)tall{
    myself.tall = tall;
}
-(void)setHumor:(BOOL)humor{
    myself.humor = humor;
}
-(BOOL)tall{
    BOOL ret = myself.tall;
    return ret;
}
-(BOOL)rich{
    BOOL ret = myself.rich;
    return ret;
}
-(BOOL)humor{
    BOOL ret = myself.humor;
    return ret;
}

这里其实只占用了一个字节,用到了其中的三位而已,,也就是 0000 0111 ,后面的三位用来存储我们的三个值,

测试代码

 Person *per = [[Person alloc] init];
    per.tall = YES;
    per.rich = NO;
    per.humor = YES;
    NSLog(@"tall : %d , rich : %d , humor : %d",per.tall,per.rich,per.humor);

我们通过断点,来查看我们的 myself 结构体的值

p/x &(per->myself) - >
((anonymous struct) *) $0 = 0x0000600002b2ae48 ,
然后查看这个地址的值 x 0x0000600002b2ae48 - >
0x600002b2ae48: 05 00 00 00 00 00 00 00 00 00 00 00 00

可以看到 05,也就是 0000 0101,也就是我们的第一位和第三位为1,和我们设置的值是一样的,由此可以证明,我们使用了一个字节中的三位,我们再来看下这个结构体的具体存储内容

p/x per->myself
((anonymous struct)) $0 = (tall = 0x01, rich = 0x00, humor = 0x01)

这次是不是一目了然。

如果发现打印为-1,是因为我们设置为1位,当要补足8位的时候,其余都补1,所以为 1111 1111 , 所以直接在get方法返回的时候 添加 !! , 也就是两个叹号就可以了,强制转化为 bool 类型

2. 联合体使用

继续上代码


#define TALL (1 << 0)
#define RICH (1 << 1)
#define HUMOR (1 << 2)
@interface Person()
{
    struct  {
        // 位域名 : 位域长
        char tall : 1;// 是否高
        char rich : 1; // 是否富有
        char humor : 1; // 是否幽默
    } myself;

//    char _my;

    union {

        char bits;

        // 增加代码的可读性,相对于这个联合体就是说这一个字节的各个位都是做什么用的,占用几位,总共是用一个字节而已
        struct {
            // 位域名 : 位域长
            char tall : 1;// 是否高
            char rich : 1; // 是否富有
            char humor : 1; // 是否幽默
        } my;

    } myUnion;
}
@end
@implementation Person

-(void)setRich:(BOOL)rich{
    if (rich) {
        myUnion.bits  |= RICH;
    } else {
        myUnion.bits  &= ~RICH;
    }

}
-(void)setTall:(BOOL)tall{
    if (tall) {
        myUnion.bits  |= TALL;
    } else {
        myUnion.bits  &= ~TALL;
    }
}
-(void)setHumor:(BOOL)humor{
    if (humor) {
        myUnion.bits  |= HUMOR;
    } else {
        myUnion.bits  &= ~HUMOR;
    }
}
-(BOOL)tall{
    BOOL ret = myUnion.bits  & TALL;
    return ret;
}
-(BOOL)rich{
    BOOL ret = myUnion.bits  & RICH;
    return ret;
}
-(BOOL)humor{
    BOOL ret = myUnion.bits  & HUMOR;
    return ret;
}

联合体


1\. 联合体中可以定义多个成员,联合体的大小由最大的成员大小决定
2\. 联合体的成员公用一个内存,一次只能使用一个成员
3\. 对某一个成员赋值,会覆盖其他成员的值
4\. 存储效率更高,可读性更强,可以提高代码的可读性,可以使用位运算提高数据的存储效率

其实这个 联合体 就是占用一个字节 ,然后联合体中可以有多个成员,但是他们是公用一块内存,第一个bits使我们真正用的,第二个定义的结构体就是为了解释这一个字节是干嘛用的,各个位是干嘛的,上面的代码我们再打印一下存储

p/x per->myUnion
((anonymous union)) $0 = {
  bits = 0x05
  my = (tall = 0x01, rich = 0x00, humor = 0x01)
}

可以看到 一目了然,下面的 my 结构体其实就是对 bits 的解释,我们设置了bits 的每一位的值,同时也是对应这个结构体里面的每一位,因为他们是共用体。 0x05 就是 0x0000 0101 ,也就是第一位和第三位为1,my = (tall = 0x01, rich = 0x00, humor = 0x01) 这个不正是告诉我们 每一位是0还是1吗?

所以 上面的代码你甚至可以这么写


-(void)setRich:(BOOL)rich{
    myUnion.my.rich  = rich;
}
-(void)setTall:(BOOL)tall{
    myUnion.my.tall  = tall;

}
-(void)setHumor:(BOOL)humor{

    myUnion.my.humor = humor;

}
-(BOOL)tall{
    BOOL ret = myUnion.bits  & TALL;
    return ret;
}
-(BOOL)rich{
    BOOL ret = myUnion.bits  & RICH;
    return ret;
}
-(BOOL)humor{
    BOOL ret = myUnion.bits  & HUMOR;
    return ret;
}

或者这么写


-(void)setRich:(BOOL)rich{
    myUnion.my.rich  = rich;
}
-(void)setTall:(BOOL)tall{
    myUnion.my.tall  = tall;

}
-(void)setHumor:(BOOL)humor{

    myUnion.my.humor = humor;

}
-(BOOL)tall{
    BOOL ret = myUnion.bits  & TALL;
    return ret;
}
-(BOOL)rich{
    BOOL ret = myUnion.bits  & RICH;
    return ret;
}
-(BOOL)humor{
    BOOL ret = myUnion.bits  & HUMOR;
    return ret;
}

或者这样


-(void)setRich:(BOOL)rich{
    myUnion.my.rich  = rich;
}
-(void)setTall:(BOOL)tall{
    myUnion.my.tall  = tall;

}
-(void)setHumor:(BOOL)humor{

    myUnion.my.humor = humor;

}
-(BOOL)tall{
    BOOL ret = myUnion.my.tall;
    return ret;
}
-(BOOL)rich{
    BOOL ret = myUnion.my.rich;
    return ret;
}
-(BOOL)humor{
    BOOL ret = myUnion.my.humor;
    return ret;
}

总结


结构体和联合体的比较

相关文章

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

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

  • Runtime源码剖析-对象

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

  • iOS联合体、位域

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

  • 联合体和位域

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

  • isa 结构分析

    我们要进行isa的分析首先掌握的知识1、联合体(共用体)1.1、使用位运算 进行 存取 数据1.2、位域 简介1....

  • 联合体&位域

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

  • iOS 知识补充: 位运算

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

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

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

  • iOS位运算及联合体位域

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

  • 联合体与位域

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

网友评论

    本文标题:iOS 知识补充: 联合体、位域

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