开发者

Forcing unaligned bitfield packing in MSVC

I've a struct of bitfields that add up to 48 bits. On GCC this correctly results in a 6 byte structure, but in MSVC the structure comes out 8 bytes. I need to find some way to force MSVC to pack the struct properly, both for interoperability and because it's being used in a memory-critical environment.

The struct seen below consists of three 15-bit numbers, one 2-bit number, and a 1-bit sign. 15+15+15+2+1 = 48, so in theory it should fit into six bytes, right?

struct S
{
  unsigned short a:15;
  unsigned short b:15;
  unsigned short c:15;
  unsigned short d:2;
  unsigned short e:1;       
};

However, compiling this on both GCC and MSVC results in sizeof(S) == 8. Thinking that this might have to do with alignment, I tried using #pragma pack(1) before the struct declaration, telling the compiler to back to byte, not int, boundaries. On GCC, this worked, resulting in sizeof(S) == 6.

However, on MSVC05, the sizeof still came out to 8, even with pack(1) set! After reading this other SO answer, I tried replacing unsigned short d with unsigned char and unsigned short e with bool. The result is sizeof(S) == 7!

I found that if I split d into two one-bit fields and wedged them in between the other members, the struct finally 开发者_StackOverflowpacked properly.

struct S
{
  unsigned short a:15;
  unsigned short dHi : 1;
  unsigned short b:15;
  unsigned short dLo : 1;
  unsigned short c:15;
  unsigned short e:1;       
};

printf( "%d\n", sizeof(S) ); // "6"

But having d split like that is cumbersome and causes trouble for me later on when I have to work on the struct. Is there some way I can force MSVC to pack this struct into 6 bytes, exactly as GCC does?


It is implementation defined how fields will be placed in the structure. Visual Studio will fit consecutive bitfields into an underlying type, if it can, and waste the leftover space. (C++ Bit Fields in VS)


If you use the type "unsigned __int64" to declare all elements of the structure, you'll get an object with sizeof(S)=8, but the last two bytes will be unused and the first six will contain the data in the format you want.

Alternatively, if you can accept some structure reordering, this will work

#pragma pack(1)
struct S3
{
  unsigned int a:15;
  unsigned int b:15;
  unsigned int d:2;
  unsigned short c:15;
  unsigned short e:1;       
};


I don't think so, and I think it's MSVC's behavior that is actually correct, and GCC that deviates from the standard.

AFAIK, the standard does not permit bitfields to cross word boundaries of the underlying type.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜