1.场景需求
1.假设一辆车需要控制前后左右4个方向或者一架无人机需要控制前后左右上5个方向,那么通常的做法是设置几个对于的bool值的属性
代码如下
由于1个BOOL值属性占用一个字节,也就是8位,总共就是 8 * 4 = 32位,对象开辟的内存大小由属性决定的,那么有没有优化的空间呢?
如果用一个字节0000 1111后四位,从低位到高位1表示是,0表示否,分别表示是否向前后左右,那么只需要1个字节,4个bit就能实现上诉功能了,此种实现方式联合体位域即可。
@interface LGCar : NSObject
@property (nonatomic, assign) BOOL front; //第0位1表示真,0表示假
@property (nonatomic, assign) BOOL back; //第1位1表示真,0表示假
@property (nonatomic, assign) BOOL left; //第2位1表示真,0表示假
@property (nonatomic, assign) BOOL right; //第3位1表示真,0表示假
@property (nonatomic, assign) char top; //第4-7位1111表示真,0000表示假
@end
2.结构体(struct)和联合体(union)的区别
结构体中所有变量是共存
的--优点有容乃大
,全面;缺点是struct内存空间的分配是粗放的
,不管用不用,全分配
。
联合体中是各变量是互斥的
--缺点就是不够包容;但优点是内存使用更为精细灵活,节省了内存空间
3.LGCar联合体位域书写方式
#import "LGCar.h"
#define LGDirectionFrontMask (1 << 0)
#define LGDirectionBackMask (1 << 1)
#define LGDirectionLeftMask (1 << 2)
#define LGDirectionRightMask (1 << 3)
#define LGDirectionTopMask (15 << 4)
@interface LGCar() {
// 联合体
union {
char bits;
// 位域
struct { // front back left right 顺序依次从低位到高位
char front : 1; // front 0 1 = 真,0 = 假
char back : 1; // back 1 1 = 真,0 = 假
char left : 1; // left 2 1 = 真,0 = 假
char right : 1; // right 3 1 = 真,0 = 假
char top: 4; // top 4-7 1111 = 真,0000 = 假
};
} _direction;
}
@end
@implementation LGCar
- (instancetype)init {
self = [super init];
if (self) {
_direction.bits = 0b00000000;
}
return self;
}
// 0000 0001
// 1111 1110
// setFront
- (void)setFront:(BOOL)isFront {
if (isFront) {
_direction.bits |= LGDirectionFrontMask;
} else {
_direction.bits &= ~LGDirectionFrontMask;
}
// 二进制打印看看 _direction.bits
[self logCharToBinarySystem:_direction.bits discription:@"setFront"];
}
// 0000 0010
// 1111 1101
// setBack
- (void)setBack:(BOOL)isBack {
if (isBack) {
_direction.bits |= LGDirectionBackMask;
} else {
_direction.bits &= ~LGDirectionBackMask;
}
// 二进制打印看看 _direction.bits
[self logCharToBinarySystem:_direction.bits discription:@"setBack "];
}
// getFront
- (BOOL)front {
char newFront = _direction.front & LGDirectionFrontMask;
[self logCharToBinarySystem:newFront discription:@"getFront"];
return newFront;
}
// getBack
- (BOOL)back {
char newBack = _direction.back & LGDirectionBackMask;
[self logCharToBinarySystem:newBack discription:@"getBack "];
return newBack;
}
- (void)setTop:(char)top {
if (top) {
_direction.bits |= LGDirectionTopMask;
} else {
_direction.bits &= ~LGDirectionTopMask;
}
[self logCharToBinarySystem:_direction.bits discription:@"setTop "];
}
- (char)top {
char newTop = _direction.bits & LGDirectionTopMask;
[self logCharToBinarySystem:newTop discription:@"getTop "];
return newTop;
}
// 二进制打印
- (void)logCharToBinarySystem:(char)value discription:(NSString *)discription {
printf("%s = ", discription.UTF8String);
for(int i = 0;i < 8; i++) {
if(value & 128)
printf("1");
else
printf("0");
value = value << 1;
}
printf(", print _direction.bits == ");
char bits = _direction.bits;
for (int i = 0; i < 8; i++) {
if(bits & 128)
printf("1");
else
printf("0");
bits =bits << 1;
if (i == 7) {
printf("\n");
}
}
}
4.调用方式
#import "LGCar.h"
void logCharToBinary(char value, char * dis) {
}
int main(int argc, char * argv[]) {
NSString * appDelegateClassName;
@autoreleasepool {
// Setup code that might create autoreleased objects goes here.
LGCar *car = [[LGCar alloc] init];
car.front = YES;
logCharToBinary(car.front, "");
car.back = YES;
logCharToBinary(car.back, "");
car.top = 0xF0;
logCharToBinary(car.top, "");
printf("\n开始清零 先front后back\n\n");
car.front = NO;
logCharToBinary(car.front, "");
car.back = NO;
logCharToBinary(car.back, "");
car.top = 0x00;
logCharToBinary(car.top, "");
appDelegateClassName = NSStringFromClass([AppDelegate class]);
}
return UIApplicationMain(argc, argv, nil, appDelegateClassName);
}
输出
setFront = 00000001, print _direction.bits == 00000001
getFront = 00000001, print _direction.bits == 00000001
setBack = 00000011, print _direction.bits == 00000011
getBack = 00000010, print _direction.bits == 00000011
setTop = 11110011, print _direction.bits == 11110011
getTop = 11110000, print _direction.bits == 11110011
开始清零 先front后back,再清零top
setFront = 11110010, print _direction.bits == 11110010
getFront = 00000000, print _direction.bits == 11110010
setBack = 11110000, print _direction.bits == 11110000
getBack = 00000000, print _direction.bits == 11110000
setTop = 00000000, print _direction.bits == 00000000
getTop = 00000000, print _direction.bits == 00000000
设置读取
front设置YES ---> 读取front
setFront = 00000001, print _direction.bits == 00000001
对字节的第0
位赋值为1
,同时不影响其他位
getFront = 00000001
,与其他位无关
back设置YES ---> 读取back
setBack = 00000011, print _direction.bits == 00000011
对字节的第1
位赋值为1
,同时不影响其他位
getBack = 00000010
,与其他位无关
top设置0xF0 ---> 读取top
setTop = 11110011, print _direction.bits == 11110011
对字节的第4-7
位赋值为1111
,同时不影响其他位
getTop = 11110000
,与其他位无关
清零读取
front清零 ---> 读取front
setFront = 11110010, print _direction.bits == 11110010
,对字节的第0
位赋值为0
,同时不影响其他位
getFront = 00000000
,与其他位无关
back清零 ---> 读取back
setBack = 11110000, print _direction.bits == 11110000
,对字节的第1
位赋值为0
,同时不影响其他位
setBack = 11110000
,与其他位无关
top清零 --->读取top
setTop = 00000000, print _direction.bits == 00000000
,对字节的第4-7
位赋值为0000
,同时不影响其他位
getTop = 00000000
,与其他位无关
5.Xcode截图
联合体位域Xcode截图.jpeg
6.总结
联合体位域
,是用一个字节
或者多个字节
其中的二进制位bit
组合到一起表示某种含义
网友评论