经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 移动开发 » iOS » 查看文章
位域-isa指针
来源:cnblogs  作者:春天里的花骨朵  时间:2019/10/10 8:50:10  对本文有异议

一、isa指针结构

  1. union isa_t
  2. {
  3. isa_t() { }
  4. isa_t(uintptr_t value) : bits(value) { }
  5. Class cls;
  6. uintptr_t bits;
  7. #if SUPPORT_PACKED_ISA
  8.  
  9. // extra_rc must be the MSB-most field (so it matches carry/overflow flags)
  10. // nonpointer must be the LSB (fixme or get rid of it)
  11. // shiftcls must occupy the same bits that a real class pointer would
  12. // bits + RC_ONE is equivalent to extra_rc + 1
  13. // RC_HALF is the high bit of extra_rc (i.e. half of its range)
  14. // future expansion:
  15. // uintptr_t fast_rr : 1; // no r/r overrides
  16. // uintptr_t lock : 2; // lock for atomic property, @synch
  17. // uintptr_t extraBytes : 1; // allocated with extra bytes
  18. # if __arm64__
  19. # define ISA_MASK 0x0000000ffffffff8ULL
  20. # define ISA_MAGIC_MASK 0x000003f000000001ULL
  21. # define ISA_MAGIC_VALUE 0x000001a000000001ULL
  22. struct {
  23. uintptr_t nonpointer : 1;
  24. uintptr_t has_assoc : 1;
  25. uintptr_t has_cxx_dtor : 1;
  26. uintptr_t shiftcls : 33; // MACH_VM_MAX_ADDRESS 0x1000000000
  27. uintptr_t magic : 6;
  28. uintptr_t weakly_referenced : 1;
  29. uintptr_t deallocating : 1;
  30. uintptr_t has_sidetable_rc : 1;
  31. uintptr_t extra_rc : 19;
  32. # define RC_ONE (1ULL<<45)
  33. # define RC_HALF (1ULL<<18)
  34. };
  35. # elif __x86_64__
  36. # define ISA_MASK 0x00007ffffffffff8ULL
  37. # define ISA_MAGIC_MASK 0x001f800000000001ULL
  38. # define ISA_MAGIC_VALUE 0x001d800000000001ULL
  39. struct {
  40. uintptr_t nonpointer : 1;
  41. uintptr_t has_assoc : 1;
  42. uintptr_t has_cxx_dtor : 1;
  43. uintptr_t shiftcls : 44; // MACH_VM_MAX_ADDRESS 0x7fffffe00000
  44. uintptr_t magic : 6;
  45. uintptr_t weakly_referenced : 1;
  46. uintptr_t deallocating : 1;
  47. uintptr_t has_sidetable_rc : 1;
  48. uintptr_t extra_rc : 8;
  49. # define RC_ONE (1ULL<<56)
  50. # define RC_HALF (1ULL<<7)
  51. };
  52. # else
  53. # error unknown architecture for packed isa
  54. # endif
  55. // SUPPORT_PACKED_ISA
  56. #endif
  57.  
  58.  
  59. #if SUPPORT_INDEXED_ISA
  60. # if __ARM_ARCH_7K__ >= 2
  61. # define ISA_INDEX_IS_NPI 1
  62. # define ISA_INDEX_MASK 0x0001FFFC
  63. # define ISA_INDEX_SHIFT 2
  64. # define ISA_INDEX_BITS 15
  65. # define ISA_INDEX_COUNT (1 << ISA_INDEX_BITS)
  66. # define ISA_INDEX_MAGIC_MASK 0x001E0001
  67. # define ISA_INDEX_MAGIC_VALUE 0x001C0001
  68. struct {
  69. uintptr_t nonpointer : 1;
  70. uintptr_t has_assoc : 1;
  71. uintptr_t indexcls : 15;
  72. uintptr_t magic : 4;
  73. uintptr_t has_cxx_dtor : 1;
  74. uintptr_t weakly_referenced : 1;
  75. uintptr_t deallocating : 1;
  76. uintptr_t has_sidetable_rc : 1;
  77. uintptr_t extra_rc : 7;
  78. # define RC_ONE (1ULL<<25)
  79. # define RC_HALF (1ULL<<6)
  80. };
  81. # else
  82. # error unknown architecture for indexed isa
  83. # endif
  84. // SUPPORT_INDEXED_ISA
  85. #endif
  86. };

分析:

1.我们知道,实例对象的isa指针指向该对象所属类的类对象;类对象的isa指向其元类对象;

2.真机为arm64架构,模拟器和mac电脑为x86架架构,以下以arm64为例讲解;

3.在64位系统下,指针所占字节为8个即64位;

4.在arm64之前,isa就是一个普通的指针,存放着类(元类)对象的地址;之后,则需要&

ISA_MASK掩码,才能获取到类(元类)对象的地址,此时isa指针为一个共用体,存储的信息不局限于类(元类)对象的地址;

5.存储信息介绍:

 

其中,shiftcls结构体成员变量(33位)用来存储类(元类)对象的地址;

 

二、类(元类)对象的地址取值原理——位域

1.结构体支持位域运算

//代码

  1. struct bs {
  2. unsigned a : 9;//如果超过位域范围(511),则只取范围内的值,其他位(高位)丢弃
  3. unsigned b : 4;
  4. unsigned c : 3;
  5. }bit, *pbit;
  6. void test1()
  7. {
  8. bit.a = 512;//超过位域范围报警告
  9. bit.b = 10;
  10. bit.c = 7;
  11. NSLog(@"%d,%d,%d\n", bit.a, bit.b, bit.c);
  12. pbit=&bit;
  13. pbit-> a=0;
  14. pbit-> b&=3;
  15. pbit-> c|=1;
  16. printf("%d,%d,%d\n ",pbit-> a,pbit-> b,pbit-> c);
  17. }

 

 

 

//输出

  1. 2019-10-08 18:22:37.051464+0800 SetAndGetsForMask[1966:248996] 0,10,7
  2. 0,2,7
  3. 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

  1. #import "Person.h"
  2.  
  3. //mask即掩码,表示二进制数(0b开头)
  4. #define TallMask (1<<0) //表示1左移0位:0b 0000 0001
  5. #define RichMask (1<<1) //表示1左移1位:0b 0000 0010
  6. #define HandsomeMask (1<<2) //表示1左移2位:0b 0000 0100
  7.  
  8. //拓展:10<<3即在10对应的二进制数后添加3个0
  9.  
  10. @interface Person()
  11. {
  12. char _saveBox;
  13. }
  14. @end
  15.  
  16. @implementation Person
  17. - (instancetype)init
  18. {
  19. if (self = [super init]) {
  20. //用一个字节来存储三个变量:从最右往左依次为Tall、Rich、Handsome
  21. _saveBox = 0b00000101;
  22. }
  23. return self;
  24. }
  25. /*思路
  26. 0000 0101(_saveBox)
  27. |0000 0001(掩码)
  28. ---------
  29. 0000 0001(赋值tall为1)
  30. 0000 0101
  31. &1111 1110(掩码取反)
  32. ---------
  33. 0000 0100(赋值tall为0)
  34. 1.如果赋的值为1,则按位或;
  35. 2.如果赋的值为0,则掩码先取反,后按位与;
  36. */
  37. - (void)setTall:(BOOL)tall
  38. {
  39. if (tall) {
  40. _saveBox |= TallMask;
  41. } else {
  42. _saveBox &= ~TallMask;
  43. }
  44. }
  45. - (void)setRich:(BOOL)rich
  46. {
  47. if (rich) {
  48. _saveBox |= RichMask;
  49. } else {
  50. _saveBox &= ~RichMask;
  51. }
  52. }
  53. - (void)setHandsome:(BOOL)handsome
  54. {
  55. if (handsome) {
  56. _saveBox |= HandsomeMask;
  57. } else {
  58. _saveBox &= ~HandsomeMask;
  59. }
  60. }
  61. /*思路
  62. 0000 0101
  63. &0000 0001
  64. ---------
  65. 0000 0001(取出tall值)
  66. 1.按位与,用掩码取出_saveBox中特定位;
  67. 2.结果>=1,取反为0,再取反为1;同理,为0则双取反后为0;
  68. */
  69. - (BOOL)isTall
  70. {
  71. return !!(_saveBox & TallMask);
  72. }
  73. - (BOOL)isRich
  74. {
  75. return !!(_saveBox & RichMask);
  76. }
  77. - (BOOL)isHandsome
  78. {
  79. return !!(_saveBox & HandsomeMask);
  80. }
  81. @end

 

//Student

  1. #import "Student.h"
  2.  
  3. @interface Student()
  4. {
  5. /*思路
  6. 1.用一个结构体来存放变量;
  7. 2.结构体支持位域:按先后顺序,一个char字符一个字节(0b0000 0000),从最右至左依次为tall、rich、handsome;
  8. */
  9. struct {
  10. char tall : 1;//用一位来存储
  11. char rich : 1;
  12. char handsome : 1;
  13. }_tallRichHandsome;
  14. }
  15. @end
  16.  
  17. @implementation Student
  18. - (void)setTall:(BOOL)tall
  19. {
  20. _tallRichHandsome.tall = tall;
  21. }
  22. - (void)setRich:(BOOL)rich
  23. {
  24. _tallRichHandsome.rich = rich;
  25. }
  26. - (void)setHandsome:(BOOL)handsome
  27. {
  28. _tallRichHandsome.handsome = handsome;
  29. }
  30. - (BOOL)isTall
  31. {
  32. return !!_tallRichHandsome.tall;//非0(包括负数)取反为0
  33. }
  34. - (BOOL)isRich
  35. {
  36. return !!_tallRichHandsome.rich;
  37. }
  38. - (BOOL)isHandsome
  39. {
  40. return !!_tallRichHandsome.handsome;
  41. }
  42. @end

 

//Worker

  1. #import "Worker.h"
  2.  
  3. #define TallMask (1<<0)//也可以左移6位,剩余位没用到
  4. #define RichMask (1<<1)
  5. #define HandsomeMask (1<<2)
  6. #define ThinMask (1<<3)
  7.  
  8. @interface Worker()
  9. {
  10. //苹果系统设计思路
  11. union {
  12. char bits;//一个字节存储结构体中的所有成员变量
  13. struct {//摆设用:位域,增加可读性
  14. char tall : 1;//占一位
  15. char rich : 1;
  16. char handsome : 1;
  17. char thin : 1;
  18. };
  19. }_tallRichHandsome;
  20. }
  21. @end
  22.  
  23. @implementation Worker
  24. - (void)setTall:(BOOL)tall
  25. {
  26. if (tall) {
  27. NSLog(@"----%c", _tallRichHandsome.bits);
  28. _tallRichHandsome.bits |= TallMask;
  29. } else {
  30. _tallRichHandsome.bits &= ~TallMask;
  31. }
  32. }
  33. - (void)setRich:(BOOL)rich
  34. {
  35. if (rich) {
  36. _tallRichHandsome.bits |= RichMask;
  37. } else {
  38. _tallRichHandsome.bits &= ~RichMask;
  39. }
  40. }
  41. - (void)setHandsome:(BOOL)handsome
  42. {
  43. if (handsome) {
  44. _tallRichHandsome.bits |= HandsomeMask;
  45. } else {
  46. _tallRichHandsome.bits &= ~HandsomeMask;
  47. }
  48. }
  49. - (void)setThin:(BOOL)thin
  50. {
  51. if (thin) {
  52. _tallRichHandsome.bits |= ThinMask;
  53. } else {
  54. _tallRichHandsome.bits &= ~ThinMask;
  55. }
  56. }
  57. - (BOOL)isTall
  58. {
  59. return !!(_tallRichHandsome.bits & TallMask);
  60. }
  61. - (BOOL)isRich
  62. {
  63. return !!(_tallRichHandsome.bits & RichMask);
  64. }
  65. - (BOOL)isHandsome
  66. {
  67. return !!(_tallRichHandsome.bits & HandsomeMask);
  68. }
  69. - (BOOL)isThin
  70. {
  71. return !!(_tallRichHandsome.bits & ThinMask);
  72. }
  73. @end

 

//main

  1. #import <Foundation/Foundation.h>
  2. #import "Person.h"
  3. #import "Student.h"
  4. #import "Worker.h"
  5. #import "Engineer.h"
  6.  
  7. struct bs {
  8. unsigned a : 9;//如果超过位域范围(511),则只取范围内的值,其他位(高位)丢弃
  9. unsigned b : 4;
  10. unsigned c : 3;
  11. }bit, *pbit;
  12. void test1()
  13. {
  14. bit.a = 512;//超过位域范围报警告
  15. bit.b = 10;
  16. bit.c = 7;
  17. NSLog(@"%d,%d,%d\n", bit.a, bit.b, bit.c);
  18. pbit=&bit;
  19. pbit-> a=0;
  20. pbit-> b&=3;
  21. pbit-> c|=1;
  22. printf("%d,%d,%d\n ",pbit-> a,pbit-> b,pbit-> c);
  23. }
  24. void test2()
  25. {
  26. Person *per = [[Person alloc] init];
  27. per.tall = NO;
  28. per.rich = NO;
  29. per.handsome = YES;
  30. NSLog(@"%d %d %d", per.isTall, per.isRich, per.isHandsome);
  31. }
  32. void test3()
  33. {
  34. Student *stu = [[Student alloc] init];
  35. stu.tall = YES;
  36. stu.rich = NO;
  37. stu.handsome = YES;
  38. NSLog(@"%d %d %d", stu.isTall, stu.isRich, stu.isHandsome);
  39. }
  40. void test4()
  41. {
  42. Worker *worker = [[Worker alloc] init];
  43. // worker.tall = YES;
  44. worker.rich = NO;
  45. worker.handsome = NO;
  46. worker.thin = YES;
  47. NSLog(@"%d %d %d", worker.isThin, worker.isRich, worker.isHandsome);
  48. }
  49. void test5()
  50. {
  51. Engineer *engineer = [[Engineer alloc] init];
  52. // engineer.age = 12;
  53. // engineer.level = 6;
  54. // engineer.workers = 5;
  55. //0b 1111 1111 1111 1111(十进制:65535)
  56. //0b 0010 1100 1110 1101(十进制:11501)
  57. engineer->_personalInfo.bits =11501;
  58. NSLog(@"%d %d %d", engineer.getAge, engineer.getLevel, engineer.getWorkers);
  59. //2019-10-08 16:42:09.612140+0800 SetAndGetsForMask[1488:127227] 7 16 8160
  60. //
  61. }
  62. int main(int argc, const char * argv[]) {
  63. @autoreleasepool {
  64. test1();
  65. // test2();
  66. // test3();
  67. // test4();
  68. // test5();
  69. }
  70. return 0;
  71. }

 

//打印

  1. 2019-10-09 10:42:04.998750+0800 SetAndGetsForMask[2513:316066] 0 0 1
  2. 2019-10-09 10:42:04.999093+0800 SetAndGetsForMask[2513:316066] 1 0 1
  3. 2019-10-09 10:42:04.999122+0800 SetAndGetsForMask[2513:316066] 1 0 0
  4. 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

  1. #import <Foundation/Foundation.h>
  2. NS_ASSUME_NONNULL_BEGIN
  3. //位域位置(变量值存储位置)
  4. #define AgeMask 0b00000111//最低三位存储
  5. #define LevelMask (1<<4)//低位往高位数,第5位存储
  6. #define WorkersMask 0b0001111111100000
  7.  
  8. @interface Engineer : NSObject
  9. {
  10. @public
  11. union {
  12. int bits;
  13. struct {//位域范围(变量值范围)
  14. int age : 3;
  15. int level : 1;
  16. int workers : 8;
  17. };
  18. }_personalInfo;
  19. }
  20. //- (void)setAge:(int)age;
  21. //- (void)setLevel:(int)level;
  22. //- (void)setWorkers:(int)workers;
  23.  
  24. - (int)getAge;
  25. - (int)getLevel;
  26. - (int)getWorkers;
  27. @end
  28. NS_ASSUME_NONNULL_END
  29. #import "Engineer.h"
  30.  
  31. @implementation Engineer
  32. //- (void)setAge:(int)age
  33. //{
  34. // self->_personalInfo.bits |= AgeMask;
  35. //}
  36. //
  37. //- (void)setLevel:(int)level
  38. //{
  39. // self->_personalInfo.bits |= LevelMask;
  40. //}
  41. //
  42. //- (void)setWorkers:(int)workers
  43. //{
  44. // self->_personalInfo.bits |= WorkersMask;
  45. //}
  46.  
  47. - (int)getAge
  48. {
  49. return self->_personalInfo.bits & AgeMask;
  50. }
  51. - (int)getLevel
  52. {
  53. return self->_personalInfo.bits & LevelMask;
  54. }
  55. - (int)getWorkers
  56. {
  57. return self->_personalInfo.bits & WorkersMask;
  58. }
  59. @end

//打印

  1. 2019-10-09 11:08:14.617655+0800 SetAndGetsForMask[2630:349068] 5 0 3296
  2. 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去打印地址,此处不再展示了)!

 

GitHub

原文链接:http://www.cnblogs.com/lybSkill/p/11641510.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号