如何访问映射内存中的位?

How to access bits in mapped memory?

想象一下!我从处理一些家庭自动化的 IO 接口收到 8 个字节作为 uint8_t data[8]。这八个字节需要解释为fallows:

如何访问正确的位? 我现在想到了两个解决方案:

解决方案 1:定义具有一些位域的结构:

struct data_s {
  uint8_t LightSwitch0:1;
  uint8_t LightSwitch1:1;
  uint8_t LightSwitch2:1;
  uint8_t LightSwitch3:1;
  uint8_t Brightness:4;
  uint8_t Dimmer0;
  uint8_t Dimmer1;
  uint8_t Dimmer2;
  uint8_t Dimmer3;
  uint8_t Dimmer4;
  uint8_t DoorSwitch:1;
  uint8_t Spare:7;
}

接下来我可以根据这个例子简单地进行转换并访问结构成员:

data_s *foo = data;
foo->LightSwtich1 = FALSE;
foo->Brightness = 7;
//...

解决方案 2:使用位掩码:

data[0] |= 0x02;
data[0] = (data[0] & 0x0F) | (( 7 << 4 ) & 0xF0)
//...

好吧,我知道位域依赖于编译器并且不那么可移植。这就是为什么通常首选解决方案 2 的原因。尽管如此,解决方案 2 看起来要复杂得多并且更难阅读。此外,如果映射内存超过八个字节,工作量会很大。

我真的需要执行解决方案 2 吗?或者我可以使用 #pragma reverse_bitfields on 指令来提高解决方案 1 的可移植性?如果代码是用交叉编译器只为一个目标构建的,我可以使用解决方案 1 吗?

所以我的问题是:我应该如何访问正确的位?

位域 compiler-dependent 的程度被夸大了。当您以奇怪的方式使用它们时,它们通常会变得很奇怪。

在您的示例中,所有字段都是无符号的并且具有相同的存储类型,其中 none 跨越存储边界,并且没有未使用的位。存在排序位的问题(如您所见),但近年来每个人都采用相同的排序。据我所知,当前的编译器不会生成任何与您获取的 IO 数据不兼容的内容。