c++ - 数组 + union + 包含位字段 C++ 的结构

标签 c++ arduino avr-gcc

我只是在玩位域,遇到了一些我不太清楚如何解决的问题。

(关于平台的注意事项:int 的大小 = 2 字节,long = 4 字节,long long = 8 字节 - 认为值得一提,因为我知道它可能会有所不同。此外,'byte' 类型被定义为 'unsigned char' )

我希望能够创建一个包含两个 36 位变量的数组,并将它们放入一个包含 9 个字节的数组的 union 中。这是我想出的:

typedef union {
  byte bytes[9];
  struct {
    unsigned long long data:36;
  } integers[2];
} Colour;

我的理论是,编译器会意识到应该有两个位域作为匿名结构的一部分,并将它们放在 9 字节的空间中。然而,事实证明它们在字节边界处对齐,因此并集占用 10 个字节而不是 9 个字节,这非常合理。

那么问题是,有没有一种方法可以像这样创建一个包含两个位字段的数组?我考虑过 'packed' 属性,但编译器只是忽略了它。

虽然这按预期工作(sizeof() 返回 9):

typedef union {
  byte bytes[9];
  struct {
    unsigned long long data0:36;
    unsigned long long data1:36;
  } integers;
} Colour;

最好将其作为数组访问。


编辑: 感谢 cdhowie 解释了为什么这行不通。

幸运的是我想到了一个方法来实现我想要的:

typedef union {
  byte bytes[9];
  struct {
    unsigned long long data0:36;
    unsigned long long data1:36;
    unsigned long long data(byte which){
      return (which?data1:data0);
    }
    void data(byte which, unsigned long long _data){
      if(which){
        data1 = _data;
      } else {
        data0 = _data;
      }
    }
  } integers; 

} Colour; 

最佳答案

如果您希望每个位域正好是 36 位宽,则不能直接使用数组来执行此操作。

指针必须与字节边界对齐,指针就是这样。由于在大多数情况下数组的功能类似于指针(有异常(exception)),这对于包含许多不能被 8 整除的位的位域来说是不可能的。(你会期望 &(((Colour *) 0)->integers[1]) 如果位域被打包则返回?什么值才有意义?)

在您的第二个示例中,位域可以紧密打包,因为幕后没有进行指针数学运算。对于可通过指针寻址的事物,它们必须落在字节边界上,因为字节是用于“测量”指针的单位。

您会注意到,如果您尝试在第二个示例中获取 (((Colour *) 0)->integers.data0)data1 的地址,正是由于这个原因,编译器将发出错误。

关于c++ - 数组 + union + 包含位字段 C++ 的结构,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12940211/

相关文章:

C 嵌套宏

c++ - g++ std::visit 泄漏到全局命名空间?

c++ - 为什么 Same_as 概念检查类型相等性两次?

c++ - 获取特定距离的键值对数组中第二大的数字

c++ - Arduino 在另一个类的构造函数中传入一个对象作为参数

c - avr-gcc Arduino atmega2560 使用太多 RAM

c++ - 为什么要在 eclipse 中使用 Cmake

c++ - 函数内部数组的动态分配

arrays - 将字节数组[十六进制]转换为字符数组或字符串类型+ Arduino

c - -gc-sections 丢弃使用过的数据