简体   繁体   中英

why size of this structure is 5 when it should be 4

I am trying to pack some data into a structure.

the structure definition is as follow:

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

Since the number of bits are 30 and pack is one, My understanding is that the size of this structure should be 4, but the compiler says that the size of it is 5 byte.

I am using Visual Studio 2012.

Please note that they are bit fields.

This has the size of 4:

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

The exact layout of bitfields in memory is not specified by the standard. However, I'm fairly convinced that if you use unsigned int for all your fields, like this:

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

your data will be packed into one 30-bit integer value. However, since you have declared the first field a char, it can not hold a 14-bit value, and thus is seen as a separate field.

(gcc gives 4 bytes for both variants, which is one reason I say that there are differences between compilers - hence nothing in the standard stating that the fields are not defined in the standard)

Because the pack pragma controls the alignment of the members. When you say 1 - it means the members are aligned at byte limits, ie a member can begin at every byte. But as you have 3 members of the size 1, 2, and 2 the resulting size is 5. If you not use it, the compiler uses usually a higher alignment than 1 as it is for the cpu far more efficient to access elements at multiple of certain values (in your case, as it occupies 6 bytes when removing the pack pragme).

Pack is not a packing of the structure on bit level.

EDIT : To clarify this statement a cite from the pack pragma doc from Visual Studio:

n(optional): Specifies the value, in bytes, to be used for packing. The default value for n is 8. Valid values are 1, 2, 4, 8, and 16. The alignment of a member will be on a boundary that is either a multiple of n or a multiple of the size of the member, whichever is smaller.

EDIT 2 (After edit from question): The reason why the bitfield in the first case get not merged (and show above behavior), is that Visual Studio only merges bitfield members of a structure into one data element, when they have the same dataype. So when all are declared short, he tries to merge them (and is successful in this case), but when one is different he cant merge.

My understanding is that the elements are packed in groups of the same type. If you replace 'char' by 'short', it will pack the ':2' with the following ':14' because 16 bits fits on the 'short'.

The merge is not done if you have 'char' followed by 'short'.

Bitfields are weird beasts anyway :)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM