位域使用 · 今天又是美好的一天!

[TOC]

位域对齐和枚举类型长度问题

问题1

​ 今天再改代码时碰到一个位域使用问题,位域是指信息在存储时,并不需要一个完整的字节,而只需要占一个或几个二进制位。又称为”位段”。所谓“位域”是把一个字节或多个字节中的二进制位划分多个部分,并指定每个域的位数。每个域定义一个域名,之后就可以通过直接调用域名进行操作。定义一个位域类型如下:

struct bs{ int a:8; int b:2; int c:6;};

​ 因为之前使用时是直接套过来的,没有了解具体的对齐方式,改动是也是一位一位往下使用的,没有出现对齐问题。这次由于要按对方设备的数据格式排列,所以在测试时出现了数值不对的现象。 去网上查到了使用和对齐规则如下:

  1. 宽度为 0 的一个未命名位域强制下一位域对齐到其下一type边界,其中type是该成员的类型。
  2. 位域的长度不能大于指定类型固有长度,比如说int的位域长度不能超过32,bool的位域长度不能超过8
  3. 位域可以无位域名,这时它只用来作填充或调整位置。无名的位域是不能使用的
  4. 如果相邻位域字段的类型相同,且其位宽之和小于类型的sizeof大小,则后面的字段将紧邻前一个字段存储,直到不能容纳为止
  5. 如果相邻位域字段的类型相同,但其位宽之和大于类型的sizeof大小,则后面的字段将从新的存储单元开始,其偏移量为其类型大小的整数倍
  6. 如果相邻的位域字段的类型不同,则各编译器的具体实现有差异,VC6采取不压缩方式(不同位域字段存放在不同的位域类型字节中),Dev-C++和GCC都采取压缩方式
  7. 如果位域字段之间穿插着非位域字段,则不进行压缩
  8. 不能对位段进行取地址操作
  9. 若位段占的二进制位数为0,则这个位段必须是无名位段,下一个位段从下一个位段存储单元开始存放
  10. 若位段出现在表达式中,则会自动进行整型升级,自动转换为int型或者unsigned int
  11. 对位段赋值时,最好不要超过位段所能表示的最大范围,否则可能会造成意想不到的结果
  12. 整个结构体的总大小为最宽基本类型成员大小的整数倍。

所以找到出错原因为配置位域时未使用字节分配给一个域名的bit大于当前字节剩余的bit位数,导致该位域从新在新的存储单元中开始分配,出现数据错位(规则5)。更改方法为将未使用域名内容分成两份,一份用于补齐当前存储单元剩余的位数,剩下的定义为另一个域名。

问题2

​ 该位域成员使用的枚举类型定义的,最开始发现问题时,怀疑是否枚举类型在使用位域存储方式会不太一样,所以将未使用的域名类型给定义为int型,发现数据正常,问题解决了!下图第一个时最开始的结构,第二个是补充适当位的结构,第三个是直接将无用位域改为int 测得3个数据结构的大小分别为5、4、4字节,所以第三个是符合规则6,进行了压缩, 另在三个结构里多分配一位得到的结构整体大小位8字节(12) 在这里插入图片描述

以上内容是在keil+c+Stm32下实现的。

原文:大专栏  位域使用 · 今天又是美好的一天!


猜你喜欢

转载自www.cnblogs.com/petewell/p/11445317.html