Ashish Kumar
Ashish Kumar

Reputation: 29

C Bitfields Size of Structures

#include <stdio.h>
int main() {
    struct on_off {
        unsigned light      : 1;
        unsigned toaster    : 1;
        int count;/* 4 bytes */
        unsigned ac         : 4;
        unsigned            : 4;
        unsigned clock      : 1;
        unsigned            : 0;
        unsigned flag       : 1;
    } kitchen;
    struct box_props {
         unsigned int opaque       : 1;
         unsigned int fill_color   : 3;
         unsigned int              : 4; 
         unsigned int show_border  : 1;
         unsigned int border_color : 3;
         unsigned int border_style : 2;
         unsigned int              : 2; 
    } s;

    printf("\n\nSize of struct on_off = %d\n", sizeof(struct on_off));
    printf("\nSize of box_props = %d\n", sizeof(struct box_props));

    return 0;
}

On compiling this program Size of struct on_off is reported to 16 whereas Size of box_props is reported to 4. Can anyone explain the reason why this happens?

Upvotes: 3

Views: 140

Answers (3)

chqrlie
chqrlie

Reputation: 145307

The sizes are different because of packing and alignment rules as outlined by Rishikesh Raje in his answer, but the behavior of your code might be undefined as you are passing a value of type size_t for a printf format %d. You should either change the format for the standard one if your compiler supports it:

printf("\nSize of struct on_off = %zu\n", sizeof(struct on_off));
printf("\nSize of box_props = %zu\n", sizeof(struct box_props));

Or use a cast for better portability to environments that do not support C99 such as Microsoft Visual Studio:

printf("\nSize of struct on_off = %d\n", (int)sizeof(struct on_off));
printf("\nSize of box_props = %d\n", (int)sizeof(struct box_props));

Upvotes: -1

Rishikesh Raje
Rishikesh Raje

Reputation: 8614

For the first structure

struct on_off{
    unsigned light      : 1;
    unsigned toaster    : 1;  // 1 byte 
                              // 3 bytes - packing to align to int border
    int count;                // 4 Bytes        
    unsigned ac         : 4;
    unsigned ss         : 4;  // 1 Byte
    unsigned clock      : 1;  // 1 byte
    unsigned            : 0;  // 2  byte -- A size of zero forces alignment to next boundary.
    unsigned flag       : 1;  // 1 byte
                              // 3 bytes -- Packing at end of struct to align to word boundary.
}
                              // 16 bytes -- Total

For the second structure

struct box_props{
     unsigned int opaque       : 1;
     unsigned int fill_color   : 3;
     unsigned int              : 4;   // 1 byte
     unsigned int show_border  : 1;
     unsigned int border_color : 3;   // 1 byte
     unsigned int border_style : 2;   
     unsigned int              : 2;   // 1 byte
                                      // 1 byte - packing at the end of structure to align to word boundary.
}
                                      // 4 bytes Total

Upvotes: 4

szym
szym

Reputation: 5846

By default C structs and C++ classes are not packed. So the count member is aligned to int boundary adding extra padding bits before it. (And structs are padded at the end to word boundary.)

On top of that unsigned : 0 is actually telling the compiler to align the struct at int boundary at that field. See also: Practical Use of Zero-Length Bitfields

So the sizeof(struct on_off) will be 4 ints. If you removed unsigned : 0 it would be 3 ints.

If you want to pack it you need to use the pack pragma or packed/aligned attributes. See: #pragma pack effect and What is the meaning of "__attribute__((packed, aligned(4))) "

Upvotes: 1

Related Questions