c++bit-fields

Struct alignment with bit-fields


Why is sizeof(A) 12?

It should be: float(4) + x_0-pad(2) + y_1(2) = 8

If it's aligned all to float, how can I avoid this?

struct A
{
    int x_0 : 1;
    int x_1 : 1;
    int x_2 : 1;
    int x_3 : 2;
    int x_4 : 2;
    int x_5 : 2;
    int x_6 : 3;
    uint16_t pad : 4;
    uint16_t y_1;
    float y_2;
};

Solution

  • Bit fields don't have a storage but they have memory location of same size as the scalar type you had supplied, therefore alignment usually is at least of same size, but order in a struct is not defined until a zero-sized field is encountered - "non-zero bit-field sequence of same type".

    In your case , on little-endian system your struct is likely either oranized like

    <32bit location #0> x_6 x_5 x_4 x_3 x_2 x_1 x_0 ... 
    <16bit location #1> pad ...    
    uint16_t      y_1;   
    float         y_2;
    

    or it can separate bytes (to not break up fields across byte borders)

    <8bit location #0> x_4 x_3 x_2 x_1 x_0 ...
    <8bit location #1> x_6 x_5 ... 
    <an optional 16bit padding>
    <16bit location #2> pad ...
    uint16_t      y_1;
    float         y_2; 
    

    Most modern compiler use first method and it's guaranteed that non-zero fields fill as much of related location as possible. That's why you got size of 12 bytes: an int (4) + 2 uint16_t(2) + float(4).

    Note: you also can encounter a compiler where an int is 16 bit and then it would work as you did expect.

    On big-endian or some flexible architectures it can be

    <32bit location #0> ... x_0 x_1 x_2 x_3 x_4 x_5 x_6 
    <16bit location #1> ... pad
    uint16_t      y_1;
    float         y_2;
    

    A different type causes new location to be considered. You can add a zero-sized field:

    int x_break: 0;
    

    anywhere to break-up the sequence and enforce partial-ordering. Unused bits marked by ... are not considered padding formally, but work similar.

    Unless aligment requrement on struct is altered by user, there can be padding before/after <location #2> pad to meet aligment requirements of int.

    Note : You cannot even guarantee that bit-fields are starting at begining of struct anymore, only that the general order in relation with other struct's members is preserved.

    Note 2 : I wrote "likely" because it's up to implementation of compiler to decide how to pack bits, but it is more or less common way to do so. It's usually same for compilers on same platform fo inter-opearability purposes, but exceptions do exist.