位域类型需要相同吗?

4

我试图得到一个明确的答案来回答这个问题。 考虑以下内容:

struct MyStruct {
    uint16_t a : 4;
    uint8_t b : 4;
}

这句话正确吗?

+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
| 15 | 14 | 13 | 12 | 11 | 10 |  9 |  8 |  7 |  6 |  5 |  4 |  3 |  2 |  1 |  0 |
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
|                                       |         b         |         a         |
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+

这是否正确?
+----+----+----+----+----+----+----+----+-----+----+----+----+----+----+----+----+----+
|    | 22 | 21 | 20 | 19 | 18 | 17 | 16 | ... |  7 |  6 |  5 |  4 |  3 |  2 |  1 |  0 |
+----+----+----+----+----+----+----+----+-----+----+----+----+----+----+----+----+----+
|                   |         b         | ... |                   |         a         |
+----+----+----+----+----+----+----+----+-----+----+----+----+----+----+----+----+----+

我想我的问题有三个方面。
1. 改变声明顺序中的类型是否会将“光标”移动到下一个类型边界?
2. 这是一个非法声明吗?
3. 如果我希望类型表示其内容的最小大小怎么办?假设我有一个64位的块,我想将其拆分为位域。即使myVar适合于uint8_t,我是否需要将每个位字段声明为uint64_t myVar:4


我会说在 b 后面有额外的填充(总共是32位而不是您所提出的16位或24位)。 - Jarod42
2个回答

2

这要看具体实现。

ISO/IEC 14882:1998 C++ 标准 (9.6 Bit-fields [class.bit]) 表示:

类对象内的位域分配是由具体实现定义的。 位域对齐也是由具体实现定义的。 位域被打包进可寻址的分配单元中。 [注意:在某些机器上,位域跨越分配单元,而在其他机器上则不跨越。在一些机器上,位域从右往左赋值,在其他机器上则从左往右赋值。]

所以……

  1. 这取决于具体实现。
  2. 这不是非法声明。
  3. 没有可移植的方法来强制类型尽可能小,如果它适合于 uint8_t,就不需要将每个位域声明为 uint64_t

1
位域的布局是由实现定义的;没有保证你会得到其中任何一个。但是类型的更改不需要编译器去到某个新边界。(另一方面,使用像 uint16_t 这样的位域类型有点傻。使用 uint16_t 的唯一原因是你需要恰好 16 位(这本身就很少见),如果你使用位域,显然不会得到 16 位。)

我这样想错了吗,即使只有前4位会被使用,a 也会在内存中占用16位,而 b 则会在内存中占用8位,即使只有前4位被使用? - bsarrazin
@bensarz,是的,你错了。这是实现定义的。实现可以做任何事情:它可以在它们之间添加3MB的填充,也可以是0位。 - Yakk - Adam Nevraumont
我接受了这个答案,因为最后一句话:“唯一使用...不会得到16位”的解释帮助我理解了我所问问题的复杂性。我在两个答案之间犹豫不决。感谢大家!! :D - bsarrazin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接