size of a structure containing bit fields

12.7k views Asked by At

Possible Duplicate:
Why isn't sizeof for a struct equal to the sum of sizeof of each member?

I was trying to understand the concept of bit fields. But I am not able to find why the size of the following structure in CASE III is coming out as 8 bytes.

CASE I:

struct B    
{
    unsigned char c;  // +8 bits
} b;

sizeof(b); // Output: 1 (because unsigned char takes 1 byte on my system)

CASE II:

struct B
{
    unsigned b: 1;
} b;

 sizeof(b); // Output: 4 (because unsigned takes 4 bytes on my system)

CASE III:

struct B
{
    unsigned char c;  // +8 bits
    unsigned b: 1;    // +1 bit
} b;

sizeof(b); // Output: 8 

I don't understand why the output for case III comes as 8. I was expecting 1(char) + 4(unsigned) = 5.

6

There are 6 answers

0
rodrigo On BEST ANSWER

You can check the layout of the struct by using offsetof, but it will be something along the lines of:

struct B
{
    unsigned char c;  // +8 bits
    unsigned char pad[3]; //padding
    unsigned int bint; //your b:1 will be the first byte of this one
} b;

Now, it is obvious that (in a 32-bit arch.) the sizeof(b) will be 8, isn't it?

The question is, why 3 bytes of padding, and not more or less?

The answer is that the offset of a field into a struct has the same alignment requirements as the type of the field itself. In your architecture, integers are 4-byte-aligned, so offsetof(b, bint) must be multiple of 4. It cannot be 0, because there is the c before, so it will be 4. If field bint starts at offset 4 and is 4 bytes long, then the size of the struct is 8.

Another way to look at it is that the alignment requirement of a struct is the biggest of any of its fields, so this B will be 4-byte-aligned (as it is your bit field). But the size of a type must be a multiple of the alignment, 4 is not enough, so it will be 8.

2
Avi On

Char are by definition a byte. ints are 4 bytes on a 32 bit system. And the struct is being padded the extra 4.

See http://en.wikipedia.org/wiki/Data_structure_alignment#Typical_alignment_of_C_structs_on_x86 for some explanation of padding

0
GriffinHeart On

To keep the accesses to memory aligned the compiler is adding padding if you pack the structure it will no add the padding.

0
rodion On

I think you're seeing an alignment effect here.

Many architectures require integers to be stored at addresses in memory that are multiple of the word size.

This is why the char in your third struct is being padded with three more bytes, so that the following unsigned integer starts at an address that is a multiple of the word size.

2
Kirill Kobelev On

The alignment and total size of the struct are platform and compiler specific. You cannot not expect straightforward and predictable answers here. Compiler can always have some special idea. For example:

struct B
{
    unsigned b0: 1;    // +1 bit
    unsigned char c;  // +8 bits
    unsigned b1: 1;    // +1 bit
};

Compiler can merge fields b0 and b1 into one integer and may not. It is up to compiler. Some compilers have command line keys that control this, some compilers not. Other example:

struct B
{
    unsigned short c, d, e;
};

It is up to compiler to pack/not pack the fields of this struct (asuming 32 bit platform). Layout of the struct can differ between DEBUG and RELEASE builds.

I would recommend using only the following pattern:

struct B
{
    unsigned b0: 1;
    unsigned b1: 7;
    unsigned b2: 2;
};

When you have sequence of bit fields that share the same type, compiler will put them into one int. Otherwise various aspects can kick in. Also take into account that in a big project you write piece of code and somebody else will write and rewrite the makefile; move your code from one dll into another. At this point compiler flags will be set and changed. 99% chance that those people will have no idea of alignment requirements for your struct. They will not even open your file ever.

0
Avi On

I took another look at this and here's what I found.

  1. From the C book, "Almost everything about fields is implementation-dependant."
  2. On my machine:
 struct B {
    unsigned c: 8;
    unsigned b: 1;
}b;
printf("%lu\n", sizeof(b));

print 4 which is a short;

You were mixing bit fields with regular struct elements.

BTW, a bit fields is defined as: "a set of adjacent bits within a sindle implementation-defined storage unit" So, I'm not even sure that the ':8' does what you want. That would seem to not be in the spirit of bit fields (as it's not a bit any more)