3

我只是在玩比特场,遇到了一些我无法弄清楚如何解决的问题。

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

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

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

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

那么问题来了,有没有办法像这样创建一个由两个位字段组成的数组?我考虑了“打包”属性,但编译器只是忽略了它。

虽然这按预期工作(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; 
4

1 回答 1

6

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

指针必须与字节边界对齐,这就是指针的方式。由于在大多数情况下(除了例外)数组的功能类似于指针,因此对于包含不能被 8 整除的多个位的位域,这是不可能的。(&(((Colour *) 0)->integers[1])如果位域被打包,您期望返回什么?什么值才有意义? ?)

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

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

于 2012-10-17T17:49:02.543 回答