位域-isa指针
一、isa指针结构
union isa_t { isa_t() { } isa_t(uintptr_t value) : bits(value) { } class cls; uintptr_t bits; #if support_packed_isa // extra_rc must be the msb-most field (so it matches carry/overflow flags) // nonpointer must be the lsb (fixme or get rid of it) // shiftcls must occupy the same bits that a real class pointer would // bits + rc_one is equivalent to extra_rc + 1 // rc_half is the high bit of extra_rc (i.e. half of its range) // future expansion: // uintptr_t fast_rr : 1; // no r/r overrides // uintptr_t lock : 2; // lock for atomic property, @synch // uintptr_t extrabytes : 1; // allocated with extra bytes # if __arm64__ # define isa_mask 0x0000000ffffffff8ull # define isa_magic_mask 0x000003f000000001ull # define isa_magic_value 0x000001a000000001ull struct { 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; # define rc_one (1ull<<45) # define rc_half (1ull<<18) }; # elif __x86_64__ # define isa_mask 0x00007ffffffffff8ull # define isa_magic_mask 0x001f800000000001ull # define isa_magic_value 0x001d800000000001ull struct { 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; # define rc_one (1ull<<56) # define rc_half (1ull<<7) }; # else # error unknown architecture for packed isa # endif // support_packed_isa #endif #if support_indexed_isa # if __arm_arch_7k__ >= 2 # define isa_index_is_npi 1 # define isa_index_mask 0x0001fffc # define isa_index_shift 2 # define isa_index_bits 15 # define isa_index_count (1 << isa_index_bits) # define isa_index_magic_mask 0x001e0001 # define isa_index_magic_value 0x001c0001 struct { uintptr_t nonpointer : 1; uintptr_t has_assoc : 1; uintptr_t indexcls : 15; uintptr_t magic : 4; uintptr_t has_cxx_dtor : 1; uintptr_t weakly_referenced : 1; uintptr_t deallocating : 1; uintptr_t has_sidetable_rc : 1; uintptr_t extra_rc : 7; # define rc_one (1ull<<25) # define rc_half (1ull<<6) }; # else # error unknown architecture for indexed isa # endif // support_indexed_isa #endif };
分析:
1.我们知道,实例对象的isa指针指向该对象所属类的类对象;类对象的isa指向其元类对象;
2.真机为arm64架构,模拟器和mac电脑为x86架架构,以下以arm64为例讲解;
3.在64位系统下,指针所占字节为8个即64位;
4.在arm64之前,isa就是一个普通的指针,存放着类(元类)对象的地址;之后,则需要&
isa_mask掩码,才能获取到类(元类)对象的地址,此时isa指针为一个共用体,存储的信息不局限于类(元类)对象的地址;
5.存储信息介绍:
其中,shiftcls结构体成员变量(33位)用来存储类(元类)对象的地址;
二、类(元类)对象的地址取值原理——位域
1.结构体支持位域运算
//代码
struct bs { unsigned a : 9;//如果超过位域范围(511),则只取范围内的值,其他位(高位)丢弃 unsigned b : 4; unsigned c : 3; }bit, *pbit; void test1() { bit.a = 512;//超过位域范围报警告 bit.b = 10; bit.c = 7; nslog(@"%d,%d,%d\n", bit.a, bit.b, bit.c); pbit=&bit; pbit-> a=0; pbit-> b&=3; pbit-> c|=1; printf("%d,%d,%d\n ",pbit-> a,pbit-> b,pbit-> c); }
//输出
2019-10-08 18:22:37.051464+0800 setandgetsformask[1966:248996] 0,10,7 0,2,7 program ended with exit code: 0
//分析
1)unsigned即无符号整型,占4个字节;结构体中成员变量所占内存相互独立且连续;
2)以a为例,所占位数为9位即0b111111111(十进制511),所以a的取值范围0~511,如果是512(二进制0b1000000000),由于只取低9位(000000000),所以取出值为0;
3)按位与&:两个都为1运算结果为1,否则为0;按位或|:两个都为0运算结果为0,否则为1;
2.参照isa,共用体套用结构体,一个char字符(一个字节)存储多个bool值并制定存储位置
2.设置类属性bool值(setter and getter)
//person
#import "person.h" //mask即掩码,表示二进制数(0b开头) #define tallmask (1<<0) //表示1左移0位:0b 0000 0001 #define richmask (1<<1) //表示1左移1位:0b 0000 0010 #define handsomemask (1<<2) //表示1左移2位:0b 0000 0100 //拓展:10<<3即在10对应的二进制数后添加3个0 @interface person() { char _savebox; } @end @implementation person - (instancetype)init { if (self = [super init]) { //用一个字节来存储三个变量:从最右往左依次为tall、rich、handsome _savebox = 0b00000101; } return self; } /*思路 0000 0101(_savebox) |0000 0001(掩码) --------- 0000 0001(赋值tall为1) 0000 0101 &1111 1110(掩码取反) --------- 0000 0100(赋值tall为0) 1.如果赋的值为1,则按位或; 2.如果赋的值为0,则掩码先取反,后按位与; */ - (void)settall:(bool)tall { if (tall) { _savebox |= tallmask; } else { _savebox &= ~tallmask; } } - (void)setrich:(bool)rich { if (rich) { _savebox |= richmask; } else { _savebox &= ~richmask; } } - (void)sethandsome:(bool)handsome { if (handsome) { _savebox |= handsomemask; } else { _savebox &= ~handsomemask; } } /*思路 0000 0101 &0000 0001 --------- 0000 0001(取出tall值) 1.按位与,用掩码取出_savebox中特定位; 2.结果>=1,取反为0,再取反为1;同理,为0则双取反后为0; */ - (bool)istall { return !!(_savebox & tallmask); } - (bool)isrich { return !!(_savebox & richmask); } - (bool)ishandsome { return !!(_savebox & handsomemask); } @end
//student
#import "student.h" @interface student() { /*思路 1.用一个结构体来存放变量; 2.结构体支持位域:按先后顺序,一个char字符一个字节(0b0000 0000),从最右至左依次为tall、rich、handsome; */ struct { char tall : 1;//用一位来存储 char rich : 1; char handsome : 1; }_tallrichhandsome; } @end @implementation student - (void)settall:(bool)tall { _tallrichhandsome.tall = tall; } - (void)setrich:(bool)rich { _tallrichhandsome.rich = rich; } - (void)sethandsome:(bool)handsome { _tallrichhandsome.handsome = handsome; } - (bool)istall { return !!_tallrichhandsome.tall;//非0(包括负数)取反为0 } - (bool)isrich { return !!_tallrichhandsome.rich; } - (bool)ishandsome { return !!_tallrichhandsome.handsome; } @end
//worker
#import "worker.h" #define tallmask (1<<0)//也可以左移6位,剩余位没用到 #define richmask (1<<1) #define handsomemask (1<<2) #define thinmask (1<<3) @interface worker() { //苹果系统设计思路 union { char bits;//一个字节存储结构体中的所有成员变量 struct {//摆设用:位域,增加可读性 char tall : 1;//占一位 char rich : 1; char handsome : 1; char thin : 1; }; }_tallrichhandsome; } @end @implementation worker - (void)settall:(bool)tall { if (tall) { nslog(@"----%c", _tallrichhandsome.bits); _tallrichhandsome.bits |= tallmask; } else { _tallrichhandsome.bits &= ~tallmask; } } - (void)setrich:(bool)rich { if (rich) { _tallrichhandsome.bits |= richmask; } else { _tallrichhandsome.bits &= ~richmask; } } - (void)sethandsome:(bool)handsome { if (handsome) { _tallrichhandsome.bits |= handsomemask; } else { _tallrichhandsome.bits &= ~handsomemask; } } - (void)setthin:(bool)thin { if (thin) { _tallrichhandsome.bits |= thinmask; } else { _tallrichhandsome.bits &= ~thinmask; } } - (bool)istall { return !!(_tallrichhandsome.bits & tallmask); } - (bool)isrich { return !!(_tallrichhandsome.bits & richmask); } - (bool)ishandsome { return !!(_tallrichhandsome.bits & handsomemask); } - (bool)isthin { return !!(_tallrichhandsome.bits & thinmask); } @end
//main
#import <foundation/foundation.h> #import "person.h" #import "student.h" #import "worker.h" #import "engineer.h" struct bs { unsigned a : 9;//如果超过位域范围(511),则只取范围内的值,其他位(高位)丢弃 unsigned b : 4; unsigned c : 3; }bit, *pbit; void test1() { bit.a = 512;//超过位域范围报警告 bit.b = 10; bit.c = 7; nslog(@"%d,%d,%d\n", bit.a, bit.b, bit.c); pbit=&bit; pbit-> a=0; pbit-> b&=3; pbit-> c|=1; printf("%d,%d,%d\n ",pbit-> a,pbit-> b,pbit-> c); } void test2() { person *per = [[person alloc] init]; per.tall = no; per.rich = no; per.handsome = yes; nslog(@"%d %d %d", per.istall, per.isrich, per.ishandsome); } void test3() { student *stu = [[student alloc] init]; stu.tall = yes; stu.rich = no; stu.handsome = yes; nslog(@"%d %d %d", stu.istall, stu.isrich, stu.ishandsome); } void test4() { worker *worker = [[worker alloc] init]; // worker.tall = yes; worker.rich = no; worker.handsome = no; worker.thin = yes; nslog(@"%d %d %d", worker.isthin, worker.isrich, worker.ishandsome); } void test5() { engineer *engineer = [[engineer alloc] init]; // engineer.age = 12; // engineer.level = 6; // engineer.workers = 5; //0b 1111 1111 1111 1111(十进制:65535) //0b 0010 1100 1110 1101(十进制:11501) engineer->_personalinfo.bits =11501; nslog(@"%d %d %d", engineer.getage, engineer.getlevel, engineer.getworkers); //2019-10-08 16:42:09.612140+0800 setandgetsformask[1488:127227] 7 16 8160 // } int main(int argc, const char * argv[]) { @autoreleasepool { test1(); // test2(); // test3(); // test4(); // test5(); } return 0; }
//打印
2019-10-09 10:42:04.998750+0800 setandgetsformask[2513:316066] 0 0 1 2019-10-09 10:42:04.999093+0800 setandgetsformask[2513:316066] 1 0 1 2019-10-09 10:42:04.999122+0800 setandgetsformask[2513:316066] 1 0 0 program ended with exit code: 0
//分析(以worker为例)
1)共用体中所有成员共同占用一块内存区,其大小等于最大那个成员所占字节数;
2)worker中的结构体并为定义变量,编译器不会计算其内存,仅是增加可读性;
3)worker中只有一个char型变量bits(占一个字节),故该共用体变量_tallrichhandsome也占一个字节;
4)结构体的位域限制变量的取值范围(一位:即0或1),mask掩码规定该变量存储的位置(在哪一位上);
3.设置类属性非bool类型(setter and getter)——限定变量值范围且指定存储位置
//engineer
#import <foundation/foundation.h> ns_assume_nonnull_begin //位域位置(变量值存储位置) #define agemask 0b00000111//最低三位存储 #define levelmask (1<<4)//低位往高位数,第5位存储 #define workersmask 0b0001111111100000 @interface engineer : nsobject { @public union { int bits; struct {//位域范围(变量值范围) int age : 3; int level : 1; int workers : 8; }; }_personalinfo; } //- (void)setage:(int)age; //- (void)setlevel:(int)level; //- (void)setworkers:(int)workers; - (int)getage; - (int)getlevel; - (int)getworkers; @end ns_assume_nonnull_end #import "engineer.h" @implementation engineer //- (void)setage:(int)age //{ // self->_personalinfo.bits |= agemask; //} // //- (void)setlevel:(int)level //{ // self->_personalinfo.bits |= levelmask; //} // //- (void)setworkers:(int)workers //{ // self->_personalinfo.bits |= workersmask; //} - (int)getage { return self->_personalinfo.bits & agemask; } - (int)getlevel { return self->_personalinfo.bits & levelmask; } - (int)getworkers { return self->_personalinfo.bits & workersmask; } @end
//打印
2019-10-09 11:08:14.617655+0800 setandgetsformask[2630:349068] 5 0 3296 program ended with exit code: 0
//说明
1)掩码mask既可以直接用二进制(0b开头)或十六进制(0x开头)表示,也可以左移符号<<表示(一般用于位域为1的情况);
2)掩码表示所占位数:1表示占住该位,0未占;并且所占位数应当是连续的,不存在两侧为1,中间为0的情况;
三、结论
1.arm64之后,isa是一个共用体类型的指针,存储内部套用的结构体中的所有成员变量;
2.根据结构体的位域来限制成员变量的值范围,用掩码来规定成员变量存储的位置,对掩码按位与运算取出特定位置的成员变量的值;
如:用bits对isa_mask按位与运算后,得到的是类(元类)对象的地址;
可以看到shiftcls成员变量位域为33位,所占bits变量的存储位置为:地位到高位第四位起,最低三位是空出来的
————因此,在arm64架构中,所有的类和元类对象地址二进制表示时最低三位都为0,十六进制表示时最低一位为0或8(这个用class和object_getclass去打印地址,此处不再展示了)!