3
#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?

chqrlie
  • 131,814
  • 10
  • 121
  • 189
  • 1
    Maybe because making it easy to align? By the way, you invoked *undefined behavior* by passing data having wrong type to `printf()`. `%zu`, not `%d`, should be used for printing `size_t`, which is returned from `sizeof` operator. – MikeCAT May 05 '16 at 04:44

3 Answers3

4

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
Rishikesh Raje
  • 8,556
  • 2
  • 16
  • 31
1

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))) "

Community
  • 1
  • 1
szym
  • 5,606
  • 28
  • 34
-1

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));
chqrlie
  • 131,814
  • 10
  • 121
  • 189