位段与共用体

位段

信息的存取一般以字节为单位。实际上,有时存储一个信息不必用一个或多个字节,例如,“真”或“假”用0或1表示,只需1位即可。在计算机用于过程控制、参数检测或数据通信领域时,控制信息往往只占一个字节中的一个或几个二进制位,常常在一个字节中放几个信息。

性质

位段(或称“位域”,Bit field)为一种数据结构,可以把数据以位的形式紧凑的储存,并允许程序员对此结构的位进行操作。这种数据结构的好处:

  • 可以使数据单元节省储存空间,当程序需要成千上万个数据单元时,这种方法就显得尤为重要。
  • 位段可以很方便的访问一个整数值的部分内容从而可以简化程序源代码。

而位域这种数据结构的缺点在于,其内存分配与内存对齐的实现方式依赖于具体的机器和系统,在不同的平台可能有不同的结果,这导致了位段在本质上是不可移植的。

共用体

在进行某些算法的C语言编程的时候,需要使几种不同类型的变量存放到同一段内存单元中。也就是使用覆盖技术,几个变量互相覆盖。这种几个不同的变量共同占用一段内存的结构,在C语言中,被称作“共用体”类型结构,简称共用体,也叫联合体。

例子

#import <Foundation/Foundation.h>

@interface JQPerson : NSObject
{
    @public
    union {
        char bits;
        struct {
            bool tall   : 1;
            bool fat    : 1;
            bool rich   : 1;
        };
    } _tallFatRich;
}

#define JQTallMask (1 << 0)
#define JQFatMask (1 << 1)
#define JQRichMask (1 << 2)

@property (nonatomic, assign, getter=isTall) BOOL tall;
@property (nonatomic, assign, getter=isFat) BOOL fat;
@property (nonatomic, assign, getter=isRich) BOOL rich;
@property (nonatomic, assign) BOOL handsome;

@end

@implementation JQPerson

- (BOOL)isTall {
    return !!(_tallFatRich.bits & JQTallMask);
}

- (void)setTall:(BOOL)tall {
    tall ? (_tallFatRich.bits |= JQTallMask) : (_tallFatRich.bits &= ~JQTallMask);
}

- (BOOL)isFat {
    return !!(_tallFatRich.bits & JQFatMask);
}

- (void)setFat:(BOOL)fat {
    fat ? (_tallFatRich.bits |= JQFatMask) : (_tallFatRich.bits &= ~JQFatMask);
}

- (BOOL)isRich {
    return !!(_tallFatRich.bits & JQRichMask);
}

- (void)setRich:(BOOL)rich {
    rich ? (_tallFatRich.bits |= JQRichMask) : (_tallFatRich.bits &= ~JQRichMask);
}

@end

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        JQPerson *person = [[JQPerson alloc] init];
        person.tall = YES;
        person.fat = NO;
        person.rich = YES;
        person.handsome = YES;
        
        NSLog(@"%lu", sizeof(typeof(person->_tallFatRich)));
        // 1
        NSLog(@"%lu", sizeof(typeof(person.handsome)));
        // 1
        
        NSLog(@"\ntall:%d\nfat:%d\nrich:%d\nhandsome:%d", person.tall, person.fat, person.rich, person.handsome);
        // tall:1
        // fat:0
        // rich:1
        // handsome:1
    }
    return 0;
}