位域-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 : ;
uintptr_t has_assoc : ;
uintptr_t has_cxx_dtor : ;
uintptr_t shiftcls : ; // MACH_VM_MAX_ADDRESS 0x1000000000
uintptr_t magic : ;
uintptr_t weakly_referenced : ;
uintptr_t deallocating : ;
uintptr_t has_sidetable_rc : ;
uintptr_t extra_rc : ;
# define RC_ONE (1ULL<<)
# define RC_HALF (1ULL<<)
}; # elif __x86_64__
# define ISA_MASK 0x00007ffffffffff8ULL
# define ISA_MAGIC_MASK 0x001f800000000001ULL
# define ISA_MAGIC_VALUE 0x001d800000000001ULL
struct {
uintptr_t nonpointer : ;
uintptr_t has_assoc : ;
uintptr_t has_cxx_dtor : ;
uintptr_t shiftcls : ; // MACH_VM_MAX_ADDRESS 0x7fffffe00000
uintptr_t magic : ;
uintptr_t weakly_referenced : ;
uintptr_t deallocating : ;
uintptr_t has_sidetable_rc : ;
uintptr_t extra_rc : ;
# define RC_ONE (1ULL<<)
# define RC_HALF (1ULL<<)
}; # else
# error unknown architecture for packed isa
# endif // SUPPORT_PACKED_ISA
#endif #if SUPPORT_INDEXED_ISA # if __ARM_ARCH_7K__ >= # define ISA_INDEX_IS_NPI
# define ISA_INDEX_MASK 0x0001FFFC
# define ISA_INDEX_SHIFT
# define ISA_INDEX_BITS
# define ISA_INDEX_COUNT ( << ISA_INDEX_BITS)
# define ISA_INDEX_MAGIC_MASK 0x001E0001
# define ISA_INDEX_MAGIC_VALUE 0x001C0001
struct {
uintptr_t nonpointer : ;
uintptr_t has_assoc : ;
uintptr_t indexcls : ;
uintptr_t magic : ;
uintptr_t has_cxx_dtor : ;
uintptr_t weakly_referenced : ;
uintptr_t deallocating : ;
uintptr_t has_sidetable_rc : ;
uintptr_t extra_rc : ;
# define RC_ONE (1ULL<<)
# define RC_HALF (1ULL<<)
}; # 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 : ;//如果超过位域范围(511),则只取范围内的值,其他位(高位)丢弃
unsigned b : ;
unsigned c : ;
}bit, *pbit; void test1()
{
bit.a = ;//超过位域范围报警告
bit.b = ;
bit.c = ;
NSLog(@"%d,%d,%d\n", bit.a, bit.b, bit.c); pbit=&bit;
pbit-> a=;
pbit-> b&=;
pbit-> c|=;
printf("%d,%d,%d\n ",pbit-> a,pbit-> b,pbit-> c);
}
//输出
-- ::37.051464+ SetAndGetsForMask[:] ,,
,,
Program ended with exit code:
//分析
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 : ;//用一位来存储
char rich : ;
char handsome : ;
}_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 : ;//占一位
char rich : ;
char handsome : ;
char thin : ;
};
}_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 : ;//如果超过位域范围(511),则只取范围内的值,其他位(高位)丢弃
unsigned b : ;
unsigned c : ;
}bit, *pbit; void test1()
{
bit.a = ;//超过位域范围报警告
bit.b = ;
bit.c = ;
NSLog(@"%d,%d,%d\n", bit.a, bit.b, bit.c); pbit=&bit;
pbit-> a=;
pbit-> b&=;
pbit-> c|=;
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 =;
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 ;
}
//打印
-- ::04.998750+ SetAndGetsForMask[:]
-- ::04.999093+ SetAndGetsForMask[:]
-- ::04.999122+ SetAndGetsForMask[:]
Program ended with exit code:
//分析(以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 : ;
int level : ;
int workers : ;
};
}_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
//打印
-- ::14.617655+ SetAndGetsForMask[:]
Program ended with exit code:
//说明
1)掩码mask既可以直接用二进制(0b开头)或十六进制(0x开头)表示,也可以左移符号<<表示(一般用于位域为1的情况);
2)掩码表示所占位数:1表示占住该位,0未占;并且所占位数应当是连续的,不存在两侧为1,中间为0的情况;
三、按位或(叠加)
typedef NS_OPTIONS(NSUInteger, UIViewAutoresizing) {
UIViewAutoresizingNone = ,
UIViewAutoresizingFlexibleLeftMargin = << ,
UIViewAutoresizingFlexibleWidth = << ,
UIViewAutoresizingFlexibleRightMargin = << ,
UIViewAutoresizingFlexibleTopMargin = << ,
UIViewAutoresizingFlexibleHeight = << ,
UIViewAutoresizingFlexibleBottomMargin = <<
}; self.view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleRightMargin;
1.分析:在iOS中,对view的自动布局经常会用到上述代码,苹果的做法是定义个枚举且每种类型都只占不同的一个二进制位,按位或相当于设定的场景都要考虑到;
2.如下代码:
typedef enum{
YBOptionTypeNone = , //0b0000
YBOptionTypeOne = <<, //0b0001
YBOptionTypeTwo = <<, //0b0010
YBOptionTypeThree = <<, //0b0100
YBOptionTypeFour = << //0b1000
}YBOptionType; void test6(YBOptionType option)
{
/*按位或叠加(包含多种情况),按位与取出(获得特定情况)
0b0001
0b0100
| 0b1000
----------
0b1101
& 0b0100
----------
0b0100
*/
if (option & YBOptionTypeOne) {
NSLog(@"contain YBOptionTypeOne");
} if (option & YBOptionTypeTwo) {
NSLog(@"contain YBOptionTypeTwo");
} if (option & YBOptionTypeThree) {
NSLog(@"contain YBOptionTypeThree");
} if (option & YBOptionTypeFour) {
NSLog(@"contain YBOptionTypeFour");
}
} int main(int argc, const char * argv[]) {
@autoreleasepool { // test1();
// test2();
// test3();
// test4();
// test5();
test6(YBOptionTypeOne | YBOptionTypeThree | YBOptionTypeFour);
}
return ;
}
//打印
-- ::17.154998+ SetAndGetsForMask[:] contain YBOptionTypeOne
-- ::17.155318+ SetAndGetsForMask[:] contain YBOptionTypeThree
-- ::17.155332+ SetAndGetsForMask[:] contain YBOptionTypeFour
Program ended with exit code:
四、结论
1.arm64之后,isa是一个共用体类型的指针,存储内部套用的结构体中的所有成员变量;
2.根据结构体的位域来限制成员变量的值范围,用掩码来规定成员变量存储的位置,对掩码按位与运算取出特定位置的成员变量的值;
如:用bits对ISA_MASK按位与运算后,得到的是类(元类)对象的地址;
可以看到shiftcls成员变量位域为33位,所占bits变量的存储位置为:地位到高位第四位起,最低三位是空出来的
————因此,在arm64架构中,所有的类和元类对象地址二进制表示时最低三位都为0,十六进制表示时最低一位为0或8(这个用class和object_getClass去打印地址,此处不再展示了)!
3.按位与作用为在集合中取出某个特定值,按位或则将若干个特定值集合到一个值中(即所有设定场景都要考虑到);
拓展:
//代码
//计算器演示
//分析
1.模拟器为x86_64架构,64位指针占八个字节;在结构体中,自上而下的变量在isa中的存储位置为从低位到高位即计算器中下到上、左到右——这点应该没问题;
2.per实例对象曾经被弱指针指向过(现在释放了),且曾经关联过对象(现在置空),而对应的位为1即表示确实曾经被弱指针指向过(如果没有则会为0),曾经关联过对象;所以
has_assoc和weakly_referenced分别表示对象曾经被弱指针指向过和曾经关联过对象——其他变量分析以此类推;
位域-isa指针的更多相关文章
- isa指针
转载自 http://www.cnblogs.com/zhangdashao/p/4438540.html 可以去这里看详细的. 每个Objective-C对象都有一个隐藏的数据结构,这个数据结构是O ...
- 关于oc运行时 isa指针详解
Cocoa框架是iOS应用程序的基础,了解Cocoa框架,对开发iOS应用有很大的帮助. 1.Cocoa是什么? Cocoa是OS X和 iOS操作系统的程序的运行环境. 是什么因素使一个程序成为Co ...
- OC self super isa指针
self指针: self是oc面向对象设计中的一个特殊指针,相当于java中的this,但是比this强大,this只能访问实例对象的相关方法和成员变量,或者说this只代表实例对象: self不仅可 ...
- iOS isa指针
在Objective-C中,任何类的定义都是对象.类和类的实例没有任何本质上的区别.任何对象都有isa指针. isa:是一个Class 类型的指针. 每个实例对象有个isa的指针,它指向对象的类,而C ...
- Runtime之IMP指针,isa指针
要了解 isa 指针先了解下类的定义在xcode中用快捷键Shift+Cmd+O 搜索objc.h 能看到类的定义:了解 Paste_Image.png 可以看出:objc_object:Object ...
- runtime运行时,类、对象、isa指针
先查看一段OC源码,关于类的定义: /// An opaque type that represents an Objective-C class. typedef struct objc_class ...
- OC 实例变量(instance var)与属性(@property)的关系 isa指针
实例变量(instance var)与属性(@property)的关系 Objective-C 2.0之后,声明一个@property name自动产生一个实例变量,名为_name,因此省去实例变量和 ...
- iOS 认识runtime 中的三个指针 isa , IMP , SEL
runtime中函数调用经常被提及的三个概念 isa,IMP,SEL 一 isa:是类指针,之所以说isa是指针是因为Class其实是一个指向objc_class结构体的指针,而isa 是它唯一的私 ...
- C/C++ 位域
//假设硬件平台是intel x86(little endian) typedef unsigned int uint32_t; void inet_ntoa(uint32_t in) { ]; re ...
随机推荐
- F#周报2019年第48期
新闻 拥抱可空引用类型 介绍Orleans 3.0 视频及幻灯片 组合的力量 关于.NET:探索新的用于.NET的Azure .NET SDK .NET设计审查:GitHub快速审查 FableCon ...
- 【JavaEE】之SSM入门项目的搭建
最近学习了一下SSM.SSM是 Spring + SpringMVC + MyBatis 整合框架,非常适合WEB后台开发,也是当前很多人的不二选择.这篇博客带大家来创建一个学习SSM的入门程序,从搭 ...
- Prometheus PromQL 简单用法
目录 说明 CPU 内存 磁盘监控 磁盘空间利用率百分比 预计饱和 说明 基于上一篇文章的基础,这里做一些关于 CPU.内存.磁盘的一些基础查询语句. CPU 通过查询 metric值为 node_c ...
- 05-kubernetes Pod控制器应用进阶
目录 Pod 资源 标签 给资源打标签 标签选择器 Pod 生命周期 实际操作 livenessProbe 实战 livenessProbe exec 测试 livenessProbe httpGet ...
- Ubuntu&Mac下使用alias简化日常操作
alias 在Linux系统中用来给指令起别名,用来简化很长的指令. 用法很简单: alias : 查看当前所有别名 alias tmstart = "$CATALINA_HOME/bin/ ...
- java关键字 保留字
Java 关键字和保留字 Java 关键字列表 (依字母排序 共51组): abstract, assert,boolean, break, byte, case, catch, char, clas ...
- linux搭建Git
安装依赖库和编译工具为了后续安装能正常进行,我们先来安装一些相关依赖库和编译工具yum install curl-devel expat-devel gettext-devel openssl-dev ...
- 小白的springboot之路(四)、mybatis-generator自动生成mapper和model、dao
0-.前言 在用mybatis开发项目中,数据库动辄上百张数据表,如果你一个一个去手动编写,比较耗费时间:还好,我们有mybatis-generator插件,只需简单几步就能自动生成mybatis的m ...
- 第五章 Unity中的基础光照(2)
目录 1. Unity中的环境光和自发光 2. 在UnityShader中实现漫反射光照模型 2.1 实践:逐顶点光照 2.2 实践:逐像素光照 2.3 半兰伯特模型 1. Unity中的环境光和自发 ...
- Python之HTTP静态Web服务器开发
众所周知,Http协议是基于Tcp协议的基础上产生的浏览器到服务器的通信协议 ,其根本原理也是通过socket进行通信. 使用HTTP协议通信,需要注意其返回的响应报文格式不能有任何问题. 响应报文, ...