使用位域时放生的问题

位域操作符:

在c++中有一种操作符 :位域操作符,他的作用是节省内存空间

规则如下:

  1. 如果相邻位域字段的类型相同,且其位宽之和小于类型的sizeof大小,则后面的字段将紧邻前一个字段存储,直到不能容纳为止;
  2. 如果相邻位域字段的类型相同,但其位宽之和大于类型的sizeof大小,则后面的字段将从新的存储单元开始,其偏移量为其类型大小的整数倍;
  3. 如果相邻的位域字段的类型不同,则各编译器的具体实现有差异,VC6采取不压缩方式,Dev-C++采取压缩方式;
  4. 如果位域字段之间穿插着非位域字段,则不进行压缩;
  5. 整个结构体的总大小为最宽基本类型成员大小的整数倍。
    原文:https://blog.csdn.net/jiyucn/article/details/862085

在开发中使用位域时,我遇到了一个错误,错误的发生,就是没有很好的计算出位域数据的大小。

typedef struct test{  
 uint8_t a1: 8;    
 uint8_t a2: 8;     
 uint8_t a3: 4;  
 uint8_t a4: 4;  
 uint8_t a5: 8;   
 uint8_t a6: 8;   
 uint8_t a7: 4;   
 uint8_t a8: 4;  
 uint16_t a9: 8;  
 uint8_t a10: 16;
 uint8_t a11 : 8;    
}test;
data = {0x55,0x1D,0xAA ,0x00,0x78,0x11,0x03,0xfd,0xfc,0xbb};

test是一个结构体变量,当中使用了位域,data是一个我们即将插入到结构体中的数据。

如果对于位域规则不熟悉,那我想当然的认为数据应该是这样对照的

a1 = 0x55;
a2 = 0x1D;
a3 = 0xA;
a4 = 0xA;
a5 = 0x00;
a6 = 0x78;
a7 = 0x1;
a8 = 0x1;
a9 = 0x03;
a10 = 0xfcfd;
a11 = 0xbb;

但是在实际的开发中,你会发现,数据的排列是这样的

a1 = 0x55;
a2 = 0x1D;
a3 = 0xA;
a4 = 0xA;
a5 = 0x00;
a6 = 0x78;
a7 = 0x1;
a8 = 0x1;
a9 = 0x03;
a10 = 0xbbfc; 
a11 = 0xcc; // 值不明确

这个问题的发生,是因为在使用位域中,如果你的数据类型不一样,则会以最大的数据类型来加载数据。

例如这个例子中:uint16_t 是最大的数据类型,则在数据赋值的过程中,会以它的字节来表示。a1 + a2 = 16bit 刚好等于一个uint16_t的长度,依次类推,a3 + a4 +a5 = 16bit a6 + a7 + a8 = 16bit也刚好等于一个uint16_t的长度,到a9时,因为已经不够 16 bit了,所以会从下个新的存储单元计算,而下个新的存储单元就是{0xfc,0xbb}了,至于0xfd则不会继续被使用。

猜你喜欢

转载自blog.csdn.net/display_chen/article/details/86514426