6

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.

4
  • 1
    you're seeing structure padding. do a search for these terms on this site and you'll find lots of information Commented Oct 6, 2012 at 17:19
  • 1
    unsigned char takes one byte on every system. Commented Oct 6, 2012 at 17:25
  • 1
    @CarlNorum: True, but that doesn't mean that a struct with one char (such as Case I) takes one byte too. A different compiler could add three bytes padding to the struct. Commented Oct 6, 2012 at 17:46
  • @MSalters, yes it most certainly could. I'm not sure I understand what you're getting at? Commented Oct 6, 2012 at 17:50

6 Answers 6

7

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.

Sign up to request clarification or add additional context in comments.

Comments

3

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.

Comments

2

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

2 Comments

in the above case3, char is 8 bits(no prob so far). and I have provided only 1 unsigned int bit. That means, the remaining 31 bits will be padded. But still the size should come as --- 8 bits(char) + 1 bit(which i have provided) + 31 bits(due to padding) == 40 bits or 4 bytes. Why it is coming as 8 bytes?
There is no way to just put a bit in any more architecture. an unsigned int is 4 bytes on your system
1

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

Comments

1

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)

Comments

1

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.

2 Comments

"Compiler can merge fields b0 and b1 into one integer and may not" - is this so? I think the compiler is required to keep the order of the bit fields.
I believe the most important principle is to "exactly preserve the observable behavior". Everything outside of this may be not as exact, may differ from compiler to compiler and from platform to platform, etc. It would be not correct to look at the black and white world, where this happens exactly this way and something else another way. A lot of things are in the grey area.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.