在讨论位域时,C ++ 17标准在第12.2.4节中多次使用术语“分配单元”,但似乎没有定义该术语的含义。该标准还指出,“作为特殊情况,宽度为零的未命名位域指定分配单元边界处下一个位字段的对齐。”
所以我对这些概念有两个问题,使用下面的代码作为例子:
在第二个问题中,我的假设是数据类型意味着后面的位字段应该在该数据类型的下一个边界上对齐。
struct tag
{
char X:3;
unsigned int :0; // start next bit-field on next unsigned int boundary?
char Y:4;
unsigned char :0; // start next bit-field on next unsigned char boundary?
long Z:32;
};
几乎所有位域的行为都是实现定义的,因此您无法查看标准以了解它们的工作原理。
“分配单位”一词故意含糊不清。它的定义实际上是暗示:
类对象中位域的分配是实现定义的。位字段的对齐是实现定义的。比特字段被打包到一些可寻址的分配单元中。 [强调补充] [class.bit] / 1
由实现来告诉你“分配单元”的含义。唯一的另一个要求是分配单元必须是“可寻址的”。这是唯一使用“可寻址”一词的地方,所以你仍然靠自己。
我认为术语“分配单元”指的是位域类型的大小。
关于bit-fields的CPP参考说明:
可以强制大小为零的特殊未命名位字段来分解填充。它指定下一个位字段从其分配单元的开头开始:
我修改了bit-fields上的CPP参考示例来说明这一点。
#include <iostream>
struct S1 {
unsigned char b1 : 1;
//unsigned char :0; // #1. start a new byte
unsigned char b2 : 1;
};
struct S2 {
unsigned int b1 : 10;
//unsigned int :0; // #2. start a new int
unsigned int b2 : 10;
};
int main()
{
std::cout << sizeof(char) << '\n';
std::cout << sizeof(int) << '\n';
std::cout << sizeof(S1) << '\n'; // usually prints 1
std::cout << sizeof(S2) << '\n'; // usually prints 4
}
S1
和S2
的大小分别为1和4,也是char
和int
的大小。这是我们通常所期望的。
但如果我在上面的结构声明中取消注释#1
和#2
,则S1
和S2
的大小将分别为2
和8
。这是您在问题中引用的陈述的结果:
作为特殊情况,宽度为零的未命名位域指定分配单元边界处的下一个位字段的对齐。