【问题标题】:sizeof pragma packed bitfield struct arraysizeof pragma 压缩位域结构数组
【发布时间】:2015-01-22 14:22:56
【问题描述】:

我将 Visual Studio 2013 用于 x64 系统。 我有以下结构:

#pragma pack(1)
    struct TimeStruct
    {
      int milliseconds  : 10;
      BYTE seconds      : 6;    
      BYTE minutes      : 6;    
      BYTE hour         : 5;    
      BYTE day          : 5;    
    };
#pragma pack()

还有一个数组:

TimeStruct stArray[10];

当我使用sizeof(stArray);时,我得到的结果是 80 而不是 40。

我需要知道问题是编译器没有正确打包还是 sizeof 没有考虑位域的实际大小。

谢谢

【问题讨论】:

  • 也许你应该使用union 而不是struct
  • 从所有供应商对位域的观点开始,C++11 § 9.6 [class.bit]:“类对象中位域的分配是实现定义的。”从来没有说过更真实的话,因为位字段是臭名昭著所以(实现定义)。

标签: c++ visual-studio-2012 sizeof pragma bit-fields


【解决方案1】:

有关 MSVC 如何处理位域的更多说明,请参阅 What is VC++ doing when packing bitfields?

它的实现取决于位域的打包和排序方式,因此请注意布局可能与您的预期不同,并且取决于您使用的特定编译器。

sizeof() 为您提供结构的大小,无论其成员是什么,因此与您的期望不同的是位域打包。

您可以从documentation 中了解布局,或使用此代码凭经验发现布局:

struct TimeStruct a;
unsigned char *b = (unsigned char*)&a;
a.milliseconds = 1;
a.seconds = 2;
a.minutes = 3;
a.hour = 3;
a.day = 4;
for(size_t i = 0; i < sizeof a; i++)
  printf("%02X ", b[i]);

 -> 64 bit compiler 01 00 00 00 02 03 04 05
 -> 32 bit compiler 01 30 FE 00 02 03 A4 65

似乎该结构为 1.int milliseconds : 10; 成员分配了一个完整的 int,然后将剩余的 3 个字节单独打包,为每个成员分配一个 BYTE,但不组合来自不同分配单元的位。

如果您对所有字段使用 int 或 unsigned int,您应该能够将其与 MSVC 编译器紧密打包,并且此结构将占用 4 个字节:

struct TimeStruct
{
  int milliseconds : 10;
  int seconds      : 6;    
  int minutes      : 6;    
  int hour         : 5;    
  int day          : 5;    
};

【讨论】:

  • 我当然没有对此投反对票,并且很想知道 OP 在running this code 时看到了什么
  • 相邻位域具有相同的内存位置。编译器可以按任何顺序为它们分配任何大小。
  • @SGrebenkin 它使用 VS2010 和 x64 配置将此结构打包成 4 个字节
  • 当然。但是您将代码 BYTE 更改为 int。它是一种类型的字段序列。因此,根据 msdn.microsoft.com/en-us/library/ewwyfdbe.aspx,您将获得 4 个字节
  • @SGrebenkin 正确。这似乎为提问者提供了解决方案。
【解决方案2】:

使用这样定义的类型存储的位字段。

int milliseconds : 10; // 4 bytes
BYTE seconds      : 6; // 1 byte
BYTE minutes      : 6; // 1 byte
BYTE hour         : 5; // 1 byte
BYTE day          : 5; // 1 byte

这就是 MSVC 2013 x64 将其存储在内存中的方式

11111111 11000000 00000000 00000000
11111100 11111100 11111000 11111000

因此,总而言之,您使用 8 个字节来存储一个结构。 8x10 是 80 个字节。一切都是正确的。

值得一提的是,gcc 的行为不同并且允许更紧密的打包。

这里解释gcc和MSVC实现的区别: Forcing unaligned bitfield packing in MSVC

【讨论】:

  • “使用像这样定义的类型存储的位字段” - 它是否记录在某处?或者它可能是 MS ABI 的一部分?
  • 并不是说编译器不能把seconds放在第二个字节中。
  • 因为标准明确说明了这一点。订单被保留
  • 标准没有规定顺序。它是特定于 MS 的,请阅读您发布的链接中的文章。但无论如何,编译器是否可以将seconds 放在第二个字节中 - 这与它们的顺序无关。
  • C++14, 1.7.13:“分配具有相同访问控制(第 11 条)的(非联合)类的非静态数据成员,以便以后的成员在类中具有更高的地址目的。”这意味着标准指定了顺序。
猜你喜欢
  • 1970-01-01
  • 2010-12-26
  • 2017-12-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多