位域使用 · 今天又是美好的一天!
Posted petewell
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了位域使用 · 今天又是美好的一天!相关的知识,希望对你有一定的参考价值。
[TOC]
位域对齐和枚举类型长度问题
问题1
? 今天再改代码时碰到一个位域使用问题,位域是指信息在存储时,并不需要一个完整的字节,而只需要占一个或几个二进制位。又称为”位段”。所谓“位域”是把一个字节或多个字节中的二进制位划分多个部分,并指定每个域的位数。每个域定义一个域名,之后就可以通过直接调用域名进行操作。定义一个位域类型如下:
struct bs int a:8; int b:2; int c:6;;
? 因为之前使用时是直接套过来的,没有了解具体的对齐方式,改动是也是一位一位往下使用的,没有出现对齐问题。这次由于要按对方设备的数据格式排列,所以在测试时出现了数值不对的现象。 去网上查到了使用和对齐规则如下:
- 宽度为 0 的一个未命名位域强制下一位域对齐到其下一type边界,其中type是该成员的类型。
- 位域的长度不能大于指定类型固有长度,比如说int的位域长度不能超过32,bool的位域长度不能超过8
- 位域可以无位域名,这时它只用来作填充或调整位置。无名的位域是不能使用的
- 如果相邻位域字段的类型相同,且其位宽之和小于类型的sizeof大小,则后面的字段将紧邻前一个字段存储,直到不能容纳为止
- 如果相邻位域字段的类型相同,但其位宽之和大于类型的sizeof大小,则后面的字段将从新的存储单元开始,其偏移量为其类型大小的整数倍
- 如果相邻的位域字段的类型不同,则各编译器的具体实现有差异,VC6采取不压缩方式(不同位域字段存放在不同的位域类型字节中),Dev-C++和GCC都采取压缩方式
- 如果位域字段之间穿插着非位域字段,则不进行压缩
- 不能对位段进行取地址操作
- 若位段占的二进制位数为0,则这个位段必须是无名位段,下一个位段从下一个位段存储单元开始存放
- 若位段出现在表达式中,则会自动进行整型升级,自动转换为int型或者unsigned int
- 对位段赋值时,最好不要超过位段所能表示的最大范围,否则可能会造成意想不到的结果
- 整个结构体的总大小为最宽基本类型成员大小的整数倍。
所以找到出错原因为配置位域时未使用字节分配给一个域名的bit大于当前字节剩余的bit位数,导致该位域从新在新的存储单元中开始分配,出现数据错位(规则5)。更改方法为将未使用域名内容分成两份,一份用于补齐当前存储单元剩余的位数,剩下的定义为另一个域名。
问题2
? 该位域成员使用的枚举类型定义的,最开始发现问题时,怀疑是否枚举类型在使用位域存储方式会不太一样,所以将未使用的域名类型给定义为int型,发现数据正常,问题解决了!下图第一个时最开始的结构,第二个是补充适当位的结构,第三个是直接将无用位域改为int 测得3个数据结构的大小分别为5、4、4字节,所以第三个是符合规则6,进行了压缩, 另在三个结构里多分配一位得到的结构整体大小位8字节(12)
以上内容是在keil+c+Stm32下实现的。
以上是关于位域使用 · 今天又是美好的一天!的主要内容,如果未能解决你的问题,请参考以下文章