A processor always aligns items to "natural" boundaries: so a 32 bit integer will always start on an address that is divisible by 32 / 8 for example (32 bits, 8 bits per byte - so the address of the integer will always be divisible by 4 with no remainder).
So your first element takes up one byte - but the next item needs to be aligned to a 32 bit boundary, so three "padding bytes" are added to get there.
The same thing happens with your
three
element - it's followed by a pointer so more padding bytes are added to get to a 64 bit boundary.
So:
Address value
00 first (8 bit byte)
01 padding
02 padding
03 padding
04 second (32 bit int)
05 second
06 second
07 second
08 three (8 bit byte)
09 padding
10 padding
11 padding
12 padding
13 padding
14 padding
15 padding
16 fourth (64 bit pointer)
17 fourth (64 bit pointer)
18 fourth (64 bit pointer)
19 fourth (64 bit pointer)
20 fourth (64 bit pointer)
21 fourth (64 bit pointer)
22 fourth (64 bit pointer)
23 fourth (64 bit pointer)
Total: 24 bytes.
To check it, swap
second
and
three
and it needs less padding:
struct test
{
unsigned char first;
unsigned char three;
int second;
struct test *fourth;
};
Address value
00 first (8 bit byte)
08 three (8 bit byte)
02 padding
03 padding
04 second (32 bit int)
05 second
06 second
07 second
08 fourth (64 bit pointer)
09 fourth (64 bit pointer)
10 fourth (64 bit pointer)
11 fourth (64 bit pointer)
12 fourth (64 bit pointer)
13 fourth (64 bit pointer)
14 fourth (64 bit pointer)
15 fourth (64 bit pointer)
Total: 16 bytes.
In fact, if you reorder them properly, you can fit all of your elements plus another value into the same space:
struct test
{
struct test *fourth;
int second;
unsigned char first;
unsigned char three;
short five;
};
Total: 16 bytes