Inaccurate size of a struct with bit fields in my book

  • A+
Category:Languages

I'm studying the basics of the C language. I arrived at the chapter of structures with bit fields. The book shows an example of a struct with two different types of data: various bools and various unsigned ints.

The book declares that the structure has a size of 16 bits and that without using padding the structure would measure 10 bits.

This is the structure that the book uses in the example:

#include <stdio.h> #include <stdbool.h>  struct test{         bool opaque                 : 1;        unsigned int fill_color     : 3;        unsigned int                : 4;        bool show_border            : 1;        unsigned int border_color   : 3;        unsigned int border_style   : 2;        unsigned int                : 2; };  int main(void) {        struct test Test;         printf("%zu/n", sizeof(Test));         return 0; } 

Why on my compiler instead does the exact same structure measure 16 bytes (rather than bits) with padding and 16 bytes without padding?

I'm using

GCC (tdm-1) 4.9.2 compiler; Code::Blocks as IDE. Windows 7 64 Bit Intel CPU 64 bit 

This is result I'm getting:

Inaccurate size of a struct with bit fields in my book

Here is a picture of the page where the example is:

Inaccurate size of a struct with bit fields in my book


The Microsoft ABI lays out bitfields in a different way than GCC normally does it on other platforms. You can choose to use the Microsoft-compatible layout with the -mms-bitfields option, or disable it with -mno-ms-bitfields. It's likely that your GCC version uses -mms-bitfields by default.

According to the documentation, When -mms-bitfields is enabled:

  • Every data object has an alignment requirement. The alignment requirement for all data except structures, unions, and arrays is either the size of the object or the current packing size (specified with either the aligned attribute or the pack pragma), whichever is less. For structures, unions, and arrays, the alignment requirement is the largest alignment requirement of its members. Every object is allocated an offset so that: offset % alignment_requirement == 0
  • Adjacent bit-fields are packed into the same 1-, 2-, or 4-byte allocation unit if the integral types are the same size and if the next bit-field fits into the current allocation unit without crossing the boundary imposed by the common alignment requirements of the bit-fields.

Since bool and unsigned int have different sizes, they are packed and aligned separately, which increases the struct size substantially. The alignment of unsigned int is 4 bytes, and having to realign three times in the middle of the struct leads to a 16 byte total size.

You can get the same behavior of the book by changing bool to unsigned int, or by specifying -mno-ms-bitfields (though this will mean you can't inter-operate with code compiled on Microsoft compilers).

Note that the standard does not specify how bitfields are laid out. So what your book says may be true for some platforms but not for all of them.

Comment

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: