欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

isa 和 联合体位域的理解

程序员文章站 2022-03-06 18:03:34
...

isa

之前说过 实例对象isa 指向类对象 类的isa 指向 元类对象
但是要 & 一个 ISA_MASK

// ISA()方法用于返回类指针
inline Class 
objc_object::ISA() 
{
    assert(!isTaggedPointer()); 
#if SUPPORT_INDEXED_ISA
    if (isa.nonpointer) {
        uintptr_t slot = isa.indexcls;
        return classForIndex((unsigned)slot);
    }
    return (Class)isa.bits;
#else
    // ISA_MASK的值是0x00007ffffffffff8ULL
    // 通过按位与的方式获取到类指针,ISA_MASK中对应的isa.bits中类指针的位数,均为1
    return (Class)(isa.bits & ISA_MASK);
#endif
}



# if __arm64__
#   define ISA_MASK        0x0000000ffffffff8ULL
# elif __x86_64__
#   define ISA_MASK        0x00007ffffffffff8ULL

为什么要 & ISA_MASK
isa 和 联合体位域的理解
isa_t 结构体
isa 和 联合体位域的理解isa 和 联合体位域的理解isa 和 联合体位域的理解

  • arm64 位之后 isa变成了一个 结构体位域 NONPOINTER_ISA 现在的isa 基本上都是被优化过的isa

NONPOINTER_ISA 苹果将 isa 设计成了联合体,在 isa 中存储了与该对象相关的一些内存的信息,但是并不需要 64 个二进制位全部都用来存储指针 因为浪费空间 所以做了优化。

位域 的操作

  • & 操作 与
    0000 0011
    0000 0010 = 0010 也就是两组数 两个都是 1 就返回1否则返回 0

    ( 如果想把某一位设值成0 只要把那一位 设置成0 其他的全设置成 1 然后做一个 & 操作 比如 0010 1010 想把第二位改为0 也就是 0010 1000 也就是
    0010 1010 & 1111 1101 ----- 两组数都是1 就返回1 有一个0 就是0 )

  • | 操作 或
    0000 0010
    0000 0011 = 0011 两组数只要有一个是1 那就是 1 否则返回0

isa 和 联合体位域的理解
为了更清楚的了解原理使用这种写法看得更清楚
isa 和 联合体位域的理解
isa 和 联合体位域的理解
查看地址 x 第一个字节 05
0000 0101 == 05

接下来说说为什么明明是1 但是log 却是 -1

aaa bbb ccc 现在设定的分别是 1位二进制位 而一个BOOL 是占一个字节8位 需要补位 全部都补1 就变成了 0b11111111
isa 和 联合体位域的理解
0xff 有符号就是-1 无符号就是255
isa 和 联合体位域的理解
只要把 aaa bbb ccc 都设置成两位 就可以解决这个问题 只要有一个0 和前面的1 分隔

公用体:大家公用一块内存

union{
        char bits;  //1个字节
        struct {    //这个结构体里的内容和 bits 公用同一块内存 1个字节8位 写不谢都行为了可读性
            char aaa : 1;        
            char bbb : 1;
            char ccc : 1;
        };
    }_ppp;
#define aaaMask (0b1111<<0)  // 0000 0000 0000 0000 0000 0000 0000 1111   4位 4位的改
#define bbbMask (0b1111<<4)  // 0000 0000 0000 0000 0000 0000 1111 0000
#define cccMask (0b1111<<8)  // 0000 0000 0000 0000 0000 1111 0000 0000

或者可以写成  1111 == 15

#define aaaMask (15<<0)  // 0000 0000 0000 0000 0000 0000 0000 1111   4位 4位的改
#define bbbMask (15<<4)  // 0000 0000 0000 0000 0000 0000 1111 0000
#define cccMask (15<<8)  // 0000 0000 0000 0000 0000 1111 0000 0000


@interface Person ()
{
    union{
        int bits;
        struct {
            char aaa : 4;
            char bbb : 4;
            char ccc : 4;
        };
    }_ppp;
}
@end

类的指针为什么 & ISA_MASK :
uintptr_t shiftcls : 33; /*MACH_VM_MAX_ADDRESS 0x1000000000*/ \
实例对象isa 指向类对象 类的isa 指向 元类对象 isa
isa 和 联合体位域的理解
isa 和 联合体位域的理解
前面有三位表示
1.指针类型
2.关联对象
3.c++析构函数
前三位代表其他的东西 不是我们需要的 我们要找的是那33 位
用33 + 3 也就是36的位置 可见全是1
也就是我们需要的 33位 & 33 个 1 可以得出这33 位的真值

位域 的实际使用

#import "ViewController.h"

//typedef enum {
//    DenumOne    = 1,    //0b0001
//    DenumTwo    = 2,    //0b0010
//    DenumThree  = 4,    //0b0100
//    DenumFour   = 8,    //0b1000
//}Denums;


typedef enum {
    DenumOne    = (1<<0),   //0b0001
    DenumTwo    = (1<<1),   //0b0010
    DenumThree  = (1<<2),   //0b0100
    DenumFour   = (1<<3),   //0b1000
}Denums;


@interface ViewController ()

@end

@implementation ViewController
//  | 运算 有一个是1 返回值就是1
//   0b0001 |
//   0b0010 |
//   0b0100 |
//--------------
//   0b0111
//  这和求和是一样的


//如果用 0b0111 和 DenumOne 0b0001 做 & 操作得到的结果
//   0b0111   0b0111   0b0111
//   0b0001   0b0010   0b1000
//------------------------------  & 操作  两个都是1 才返回1 否则返回0 用总和  和自身做&操作 还是自己
//   0b0001   0b0010   0b0000 总和  和 0b1000做 &操作 就都是0

- (void)setDenum:(Denums)enums
{
    if (enums & DenumOne) {
        NSLog(@"有1");
    }
    
    if (enums & DenumTwo) {
        NSLog(@"有2");
    }
    
    if (enums & DenumThree) {
        NSLog(@"有3");
    }
    
    if (enums & DenumFour) {
        NSLog(@"有1");
    }
}
- (void)viewDidLoad {
    [super viewDidLoad];
    [self setDenum:DenumOne | DenumTwo | DenumThree];
}


2020-02-18 13:30:24.513855+0800 blockTest[25965:10829655]1
2020-02-18 13:30:24.513967+0800 blockTest[25965:10829655]2
2020-02-18 13:30:24.514094+0800 blockTest[25965:10829655]3
相关标签: Xcode