Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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;
};
like image 442
mans Avatar asked May 29 '13 12:05

mans


2 Answers

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)

like image 76
Mats Petersson Avatar answered Oct 12 '22 23:10

Mats Petersson


Because the pack pragma controls the alignment of the members. When you say 1 - it means the members are aligned at byte limits, i.e. 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.

like image 31
flolo Avatar answered Oct 12 '22 23:10

flolo