Smallest size of bit field

Viewed 1829

I have some problems with understanding results returned by sizeof.

Let assume that I have two structs:

typedef struct{
    unsigned int  age    : 4;
    unsigned char gender : 1;
    unsigned int  size   : 2;
} child_t;

typedef struct{
    unsigned int  age    : 4;
    unsigned char gender : 1;
    unsigned int  size   : 2;
} __attribute__((packed)) child_t_packed;

https://coliru.stacked-crooked.com/view?id=10866c66fe82f4e4

Could you explain why the size of the first struct is 4 bytes?

Probably I am wrong, but I expected 2 bytes. (4 bits in the first row and 3 bits in the second row).

The packed version ignores alignment and in the second case sizeof(child_t_packed) = 1 byte. Does it mean that 1 byte is the smallest size a variable of the type child_t_packed may occupy in memory? or the smallest value could be 7 bits?

2 Answers

The size of child_t is four bytes because the implementation decides to align the struct same as unsigned int, which is the type of age and size.

Allocation of bit-fields within a class object is implementation-defined. Alignment of bit-fields is implementation-defined. Bit-fields are packed into some addressable allocation unit.

See [class.bit]

If child_t consisted only of unsigned char bit field members, then the alignment would be that of unsigned char and the whole struct would (most likely, it's still implementation-defined) fit into a single byte.

typedef struct{
    unsigned char age     : 4;
    unsigned char gender  : 1;
    unsigned char size    : 2;
} child_t_char;

See https://godbolt.org/z/MGKPqGPKq

child_t_packed is of size 1 because we enforce minimal padding using the packed attribute.

The packed attribute specifies that a structure member should have the smallest possible alignment—one bit for a bit-field and one byte otherwise, unless a larger value is specified with the aligned attribute. The attribute does not apply to non-member objects.

See GCC 11 documentation on variable attributes

Since 4+1+2 bits fit into a single byte, the size is 1. This means that an object of type child_t_packed will occupy exactly one byte in memory.

In standard C++, the smallest possible size of a struct is 1 char (which is at least 8 bits). So even an extension like __attribute__((packed)) is forced to yield a struct of size 1.

Furthermore, almost everything about the layout of bit-fields is implementation-defined.

In this example it seems GCC simply picks the alignment of the largest specified member type (int) for the bit-field alignment.

If you change int to short, then sizeof(child_t) will yield 2:

typedef struct{
    unsigned short age    : 4;
    unsigned char  gender : 1;
    unsigned short size   : 2;
} child_t;

https://coliru.stacked-crooked.com/a/3db0b400312e3d2c

Related