理解用C ++编写的位域填充

时间:2014-04-30 05:22:40

标签: c++

我正在尝试理解位域。以下示例显示在C++ online docs

#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位未使用。为什么? Shoudn是无符号字符类型中的位数 - 定义的位数?还是未分配的位数留给下一个分配单元边界?

3 个答案:

答案 0 :(得分:1)

将所有字段声明打包到一行中会使得查看正在进行的操作变得有点困难。这是同样的事情,但重新格式化:

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)

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

答案 1 :(得分:1)

我不同意您正在阅读的文档。引用C ++标准&#34;类对象中位域的分配是实现定义的&#34;。

某些编译器会扩展位字段。如果你这样做

unsigned x : 3 ;

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

unsigned x : 1 ;

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

你正在处理那些完全错误的材料。如果你想使用实际位,你可以:

1)需要确切知道编译器如何进行布局;要么 2)使用位掩码和&lt;&lt;&lt;,&amp;,|,&gt;&gt;运算符将值提取并插入已知大小的整数。

答案 2 :(得分:0)

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

#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个字节。顺便说一句,你可以阅读评论中的“通常”这个词是有原因的。