C语言位域详解和实例分析

2020-09-28  本文已影响0人  002and001

前言

在探究OC底层源码的时候,涉及到了联合体和位域相关知识。比如objc_objct里面的isa_t就是一个联合体,isa_t里面就有位域类型的数据。今天我们就来好好学习一下位域

目录.png

简介

  位域,也称位段,在C语言中,位段的声明和结构(struct)类似,但它的成员是一个或多个位的字段,这些不同长度的字段实际储存在一个或多个整型变量中。在声明时,位段成员必须是整形或枚举类型(通常是无符号类型),且在成员名的后面是一个冒号和一个整数,整数规定了成员所占用的位数。
  位域不能是静态类型。不能使用&对位域做取地址运算,因此不存在位域的指针,编译器通常不支持位域的引用(reference)。

以下程序则展示了一个位段的声明:

struct CHAR 
{
    unsigned int ch   : 8;    //8位
    unsigned int font : 6;    //6位
    unsigned int size : 18;   //18位
};
struct CHAR ch1;

以下程序展示了一个结构体的声明:

struct CHAR2 
{
    unsigned char ch;    //8位
    unsigned char font;  //8位
    unsigned int  size;  //32位
};
struct CHAR2 ch2;

  第一个声明取自一段文本格式化程序,应用了位段声明。它可以处理256个不同的字符(8位),64种不同字体(6位),以及最多262,144个单位的长度(18位)。这样,在ch1这个字段对象中,一共才占据了32位的空间。而第二个程序利用结构体进行声明,可以看出,处理相同的数据,CHAR2类型占用了48位空间,如果考虑边界对齐并把要求最严格的int类型最先声明进行优化,那么CHAR2类型则要占据64位的空间。

实例分析

下面的demo例子输出什么

struct BitFields {
    unsigned int bit1 : 1;
    unsigned int bit2 : 1;
    unsigned int bit3 : 4;
    unsigned int bit4 : 2;
};

union my_isa_t {
    unsigned int bitfields;
    
    unsigned int bit1 : 1;
    unsigned int bit2 : 1;
    unsigned int bit3 : 4;
    unsigned int bit4 : 2;
};


union my_new_isa_t {
    unsigned int bitfields;
    struct {
        unsigned int bit1 : 1;
        unsigned int bit2 : 1;
        unsigned int bit3 : 4;
        unsigned int bit4 : 2;
    };
};

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        // insert code here...
        NSLog(@"Hello, World!");
        
        struct BitFields bitFields = {};
        bitFields.bit1 = 0b0;
        bitFields.bit2 = 0b1;
        bitFields.bit3 = 0b1010;
        bitFields.bit4 = 0b11;
        
        union my_isa_t isa = {};
        isa.bitfields = 0b00000011;
        isa.bit1 = 0b0;
        isa.bit2 = 0b1;
        isa.bit3 = 0b1010;
        isa.bit4 = 0b11;
        
        union my_new_isa_t newIsa = {};
        newIsa.bitfields = 0b00000011;
        newIsa.bit1 = 0b0;
        newIsa.bit2 = 0b1;
        newIsa.bit3 = 0b1010;
        newIsa.bit4 = 0b11;
 
        NSLog(@"sizeof(bitfileds):%lu",sizeof(bitFields));
        NSLog(@"bitFields.bit1:%d",bitFields.bit1);
        NSLog(@"bitFields.bit2:%d",bitFields.bit2);
        NSLog(@"bitFields.bit3:%d",bitFields.bit3);
        NSLog(@"bitFields.bit4:%d",bitFields.bit4);
        
        NSLog(@"sizeof(isa):%lu",sizeof(isa));
        NSLog(@"isa.bit1:%d",isa.bit1);
        NSLog(@"isa.bit2:%d",isa.bit2);
        NSLog(@"isa.bit3:%d",isa.bit3);
        NSLog(@"isa.bit4:%d",isa.bit4);
        NSLog(@"isa.bitfileds:%d",isa.bitfields);
        
        NSLog(@"sizeof(newIsa):%lu",sizeof(newIsa));
        NSLog(@"newIsa.bit1:%d",newIsa.bit1);
        NSLog(@"newIsa.bit2:%d",newIsa.bit2);
        NSLog(@"newIsa.bit3:%d",newIsa.bit3);
        NSLog(@"newIsa.bit4:%d",newIsa.bit4);
        NSLog(@"newIsa.bitfields:%d",newIsa.bitfields);
        
        NSLog(@"0b1111:%d",0b1111);
    
    }
    return 0;
}

  struct BitFileds 很多人都能理解,但是对union my_new_isa_t以及union my_isa_t 可能存在疑惑,我们一一进行分析:

struct BitFileds

struct BitFileds {
    unsigned int bit1 : 1;
    unsigned int bit2 : 1;
    unsigned int bit3 : 4;
    unsigned int bit4 : 2;
};

union my_isa_t

union my_isa_t {
    unsigned int bitfileds;
    
    unsigned int bit1 : 1;
    unsigned int bit2 : 1;
    unsigned int bit3 : 4;
    unsigned int bit4 : 2;
};

union my_new_isa_t

union my_new_isa_t {
    unsigned int bitfileds;
    struct {
        unsigned int bit1 : 1;
        unsigned int bit2 : 1;
        unsigned int bit3 : 4;
        unsigned int bit4 : 2;
    };
};

整体内存结构图如下

联合体&结构体&位域.png

结合demo中的三个例子大家应该对位域有了深入的理解,对于位段成员类型不一致的情况,这里就不展开了,大家可以结合规则进行内存分析。

isa_t位域分析

union isa_t {
    isa_t() { }
    isa_t(uintptr_t value) : bits(value) { }

    Class cls;
    uintptr_t bits;
#if defined(ISA_BITFIELD)
    struct {
        ISA_BITFIELD;  // defined in isa.h
    };
#endif
};

# if __arm64__
#   define ISA_MASK        0x0000000ffffffff8ULL
#   define ISA_MAGIC_MASK  0x000003f000000001ULL
#   define ISA_MAGIC_VALUE 0x000001a000000001ULL
#   define ISA_BITFIELD                                                      \
      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
#   define ISA_BITFIELD                                                        \
      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

思考

// 在arm64下将位域换成基本数据类型
struct isa_t_notBitFields {
    unsigned char nonpointer;  // 1字节
    unsigned char has_assoc; // 1字节
    unsigned char has_cxx_dtor; // 1字节
    unsigned long shiftcls; // 8字节
    unsigned char magic; // 1字节
    unsigned char weakly_referenced; // 1字节
    unsigned char deallocating; // 1字节
    unsigned char has_sidetable_rc; // 1字节
    unsigned int extra_rc; // 4字节
};

总结

BitFieldDemo-源码

参考
百度百科-位域
C语言位域(位段)详解

上一篇 下一篇

猜你喜欢

热点阅读