tags:

views:

260

answers:

6

I have the following struct declaration and typedef in my code:

struct blockHeaderStruct {
    bool allocated;
    unsigned int length;
};
typedef struct blockHeaderStruct blockHeader;

When I do sizeof(blockheader), I get the value of 4 bytes back, but when I do sizeof(blockHeaderStruct), I get 8 bytes.

Why is this happening? Why am I not getting 5 back instead?

A: 

Some compilers will optimize to always allocate data by powers of 2 (4 stays 4, but 5 is rounded up to 8).

magicdanw
Wouldn't that get rid of the boolean value though?
samoz
Typically variables are aligned by their own individual size.
Potatoswatter
I don't know the sizes of each data type on your platform, but if you were expecting 5 and got 8, this is why.
magicdanw
@PotatoswatterNot true for 64bit variables on x86-32 which are generally 4 byte aligned.http://en.wikipedia.org/wiki/Data_structure_alignment#x86_and_x86-64
tristopia
+2  A: 

Looking at the definition of your struct, you have 1 byte value followed by 4 byte Integer. This integer needs to be allocated on 4 byte boundary, which will force compiler to insert a 3 byte padding after your 1 byte bool. Which makes the size of struct to 8 byte. To avoid this you can change order of elements in the struct.

Also for two sizeof calls returning different values, are you sure you do not have a typo here and you are not taking size of pointer or different type or some integer variable.

Rohit J
Changing the order of elements will sometimes reduce padding, but not in this case.
Potatoswatter
+4  A: 

Firstly, you cannot do sizeof(blockHeaderStruct). That simply will not compile. What you can do is sizeof(struct blockHeaderStruct), which could indeed give you 8 bytes as result.

Secondly, getting a different result from sizeof(blockheader) is highly unlikely. Judging by your reference to sizeof(blockHeaderStruct) (which, again, will not even compile) your description of the problem is inaccurate. Take a closer look at what is it you are really doing. Most likely, you are taking a sizeof of a pointer type (which gives you 4), not a struct type.

In any case, try posting real code.

AndreyT
sizeof(blockHeaderStruct) compiled just fine for me in g++ 4.2 (note this is tagged C++ not C).
Mark B
@Mark B: This was tagged C originally, and retagged C++ only 7 hours ago. My answer was posted 18 hours ago.
AndreyT
+1  A: 

The most likely scenario is that you are actually looking at the size of a pointer, not the struct, on a 32-bit system.

However, int may be 2 bytes (16 bits). In that case, the expected size of the structure is 4:

  • 2 bytes for the int
  • 1 byte for the bool
  • round up to the next multiple of 2, because the size of the struct is usually rounded to a multiple of the size of its largest primitive member.

Nothing could explain sizeof(blockHeaderStruct) != sizeof(struct blockHeader), though, given that typedef. That is completely impossible.

Potatoswatter
A: 

I actually copied that snippet direct from my source file.

OK.

When I do sizeof(blockheader), I get the value of 4 bytes back

It looks like blockheader is typedef'ed somewhere and its type occupies 4 bytes or its type requires 4 byte alignment.

If you try sizeof(blockHeader) you'll get your type.

when I do sizeof(blockHeaderStruct), I get 8 bytes.

The reason why alignment matters is that if you need an array of blockHeaders then you can compute how much memory you need. Or if you have an array and need to compute how much memory to copy, you can compute it.

If you want to align all struct members to addresses that are multiples of 1 instead of 4 or instead of your compiler's defaults, your compiler might offer a #pragma to do it. Then you'll save memory but accesses might be slower in order to access unaligned data.

Windows programmer
and the name of that pragma on almost all compilers is `#pragma align`.
Potatoswatter
A: 

Struct allocation normally occurs on a 4 byte boundary. That is the compiler will pad data types within a struct up to the 4 byte boundary before starting with the next data type. Given that this is c++ (bool is a sizeof 1) and not c (bool needs to be #define as something)

    struct blockHeaderStruct {
       bool allocated;         // 1 byte followed by 3 pad bytes
       unsigned int length;    // 4 bytes
    };
    typedef struct blockHeaderStruct blockHeader;
    typedef struct blockHeaderStruct *blockHeaderPtr;

A sizeof operation would result:

sizeof(blockHeader) == 8
sizeof(struct blockHeader) == 8
sizeof(blockHeaderPtr) == 4

(Note: The last entry will be 8 for a 64 bit compiler. )

There should be no difference in sizes between the first two lines of code. A typedef merely assigns an alias to an existing type. The third is taking the sizeof a pointer which is 4 bytes in a 32 bit machine and 8 bytes on a 64 bit machine.


To fix this, simply apply the #pragma pack directive before a structure is defined. This forces the compiler to pack on the specified boundary. Usually set as 1,2,or 4 (although 4 is normally the default and doesn't need to be set).

#include <stddef.h>
#include <stdio.h>

#pragma pack(1)
struct blockHeaderStruct {
    bool allocated;
    unsigned int length;
};
typedef struct blockHeaderStruct blockHeader;

int main()
{
    printf("sizeof(blockHeader) == %li\n", sizeof(blockHeader));
    printf("sizeof(struct blockHeader) == %li\n", sizeof(struct blockHeaderStruct));

    return 0;
}

Compiled with g++ (Ubuntu 4.4.1-4ubuntu9) 4.4.1

Results in:

sizeof(blockHeader) == 5  
sizeof(structblockHeader) == 5

You don't normally need this directive. Just remember to pack your structs efficiently. Group smaller data types together. Do not alternate < 4 byte datatypes and 4 byte data types as your structs will be mostly unused space. This can cause unnecessary bandwidth for network related applications.

incognick