5

我正在尝试将一些数据打包到一个结构中。

结构定义如下:

#pragma pack(push)
#pragma pack(1)
struct Data
{
    unsigned char i:2;
    unsigned short r:14;
    unsigned short c:14;
};
#pragma pack(pop)

由于位数是 30,pack 是 1,我的理解是这个结构的大小应该是 4,但是编译器说它的大小是 5 字节。

我正在使用 Visual Studio 2012。

请注意,它们是位域。

它的大小为 4:

struct Data
{
    unsigned short i:2;
    unsigned short r:14;
    unsigned short c:14;
};
4

3 回答 3

8

标准未指定内存中位域的确切布局。但是,我相当确信,如果您使用unsigned int所有领域,就像这样:

struct Data
{
    unsigned int i:2;
    unsigned int r:14;
    unsigned int c:14;
};

您的数据将被打包成一个 30 位整数值。但是,由于您已将第一个字段声明为 char,它不能保存 14 位值,因此被视为一个单独的字段。

(gcc 为两种变体提供 4 个字节,这是我说编译器之间存在差异的原因之一 - 因此标准中没有任何内容说明标准中未定义字段)

于 2013-05-29T13:03:24.150 回答
3

因为 pack pragma 控制成员的对齐方式。当您说 1 - 这意味着成员在字节限制处对齐,即成员可以从每个字节开始。但是由于您有 3 个大小为 1、2 和 2 的成员,因此结果大小为 5。如果您不使用它,编译器通常使用比 1 更高的对齐方式,因为它使 cpu 更有效地访问多个元素某些值(在您的情况下,因为它在删除 pack pragme 时占用 6 个字节)。

Pack 不是位级别结构的打包。

编辑:为了澄清这个声明,引用了 Visual Studio 的 pack pragma doc:

n(可选):指定用于打包的值,以字节为单位。n 的默认值为 8。有效值为 1、2、4、8 和 16。成员的对齐方式将位于 n 的倍数或成员大小的倍数的边界上,以两者为准更小。

编辑2(从问题编辑后):第一种情况下的位域未合并(并显示上述行为)的原因是,Visual Studio 仅将结构的位域成员合并到一个数据元素中,当它们具有相同的数据类型时. 因此,当所有内容都被宣布为短时,他会尝试合并它们(在这种情况下是成功的),但是当一个不同时,他无法合并。

于 2013-05-29T13:04:36.930 回答
2

我的理解是元素被打包在相同类型的组中。如果将 'char' 替换为 'short',它将使用以下 ':14' 打包 ':2',因为 16 位适合 'short'。

如果您有 'char' 后跟 'short',则合并不会完成。

无论如何,位域都是奇怪的野兽:)

于 2013-05-29T13:05:07.080 回答