sizeof pragma packed bitfield struct 数组
sizeof pragma packed bitfield struct array
我使用 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 没有考虑位域的实际大小。
谢谢
有关 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;
};
像这样使用定义的类型存储的位字段。
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
我使用 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 没有考虑位域的实际大小。
谢谢
有关 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;
};
像这样使用定义的类型存储的位字段。
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