在讨论位字段时,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;
};
答案 0 :(得分:4)
几乎所有位域的行为都是由实现定义的,因此您无法查看标准以了解其工作原理的详细信息。
“分配单位”一词故意含糊。它的定义实际上是含蓄的:
在类对象中分配位域是 实现定义的。位域的对齐方式是 实现定义的。位字段打包成一些可寻址的 分配单位。 [强调] [class.bit] / 1
由实现来告诉您“分配单元”是什么意思。唯一的其他要求是分配单元必须是“可寻址的”。这是唯一使用“可寻址”一词的地方,因此您仍然自己一个人。
答案 1 :(得分: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
。这是您在问题中引用的语句的结果:
在特殊情况下,宽度为零的未命名位域指定下一个位域在分配单元边界处的对齐。”