理解C++中的位字段封装

Understanding Bit Fields packing in C++

本文关键字:字段 封装 C++ 理解      更新时间:2023-10-16

我正在努力理解位字段。以下示例出现在C++联机文档中。

#include <iostream>
struct S {
// will usually occupy 2 bytes:
// 3 bits: value of b1
// 2 bits: unused
// 6 bits: value of b2
// 2 bits: value of b3
// 3 bits: unused
unsigned char b1 : 3, : 2, b2 : 6, b3 : 2;
};
int main()
{
    std::cout << sizeof(S) << 'n'; // usually prints 2
}

关于这个例子,我不明白的是,在代码上方的注释中,说b1:3之后有2个比特未使用。然后在b3:2之后,有3个比特未被使用。为什么?这不应该是无符号字符类型定义的位数吗?或者留给下一个分配单元边界的未被支持的比特的数量?

将所有字段声明打包到一行会使查看发生了什么有点困难

struct S {
  unsigned char b1:3;  // 3 bits - b1
  unsigned char   :2;  // 2 bits - unused
  unsigned char b2:6;  // 6 bits - b2
  unsigned char b3:2;  // 2 bits - b3
                       // Total: 13 bits
};                     // 3 bits - unused (implicit padding)

两个"未使用"部分是:(1(b1之后的未命名字段,显式宽度为2位;以及(2(在结构的末尾进行填充以将其四舍五入为16位(下一个unsigned char单元(。

我不同意您正在阅读的文档。引用C++标准"类对象中位字段的分配是由实现定义的"。

一些编译器扩展位字段。如果你做

unsigned x : 3 ;

编译器几乎可以为分配做任何它想做的事情。我有一些采用的编译器

unsigned x : 1 ;

并将其转换为32位整数(提供最佳性能(。

你所处理的材料完全是错误的。如果你想使用实际的比特,你可以:

1( 需要确切地知道编译器是如何进行布局的;或2( 使用位掩码和<lt&,|,>>运算符,用于提取值并将其插入到已知大小的整数中。

您正在处理未命名变量。这将更容易理解:

#include <iostream>
struct S {
    // will usually occupy 2 bytes:
    // 3 bits: value of b1
    // 2 bits: unused
    // 6 bits: value of b2
    // 2 bits: value of b3
    // 3 bits: unused
    unsigned char b1 : 3;
    unsigned char : 2; // How do you reference these?
    unsigned char b2 : 6, b3 : 2;
};
int main()
{
    std::cout << sizeof(S) << 'n'; // usually prints 2
}

http://ideone.com/6eCUB0

未命名的是没有名称的变量,因此不能以正常方式引用它们。在一天结束的时候,在你的情况下,它们只是占用了一些空间,可能会被用于填充、对齐或其他适合这个样本的原因。

如果你把所有这些比特加起来,你会得到16个,在大多数系统上正好是2个字节。顺便说一句,正如你所读到的,评论中的">通常"一词是有原因的。