Because of structure packing. many processors required that variables of a given byte size start on a given byte boundary. Often the boundary is the number of bytes in a the variable up to a given size (often 4) so
1 byte size variables have to start on a 1 byte boundary (i.e. any boundary)
2 byte size variables have to start on a 2 byte boundary address%2 = 0
4 or greater byte size variables have to start on a 4 byte boundary address%4 = 0
This is only 1 scheme there are many schemes which will be different for different processors.
Also generally a structure needs to start on the largest available byte boundary (4 in the above case) to maintain the alignment of it's members, therefore in order to facilitate having a array of structures the structure must end on the required boundary and if necessary padding bytes are added to the end of the structure.
consider these 2 structures
-
struct tag_s1 {
-
char c;
-
long l1;
-
short s;
-
long l2;
-
} s1;
-
-
struct tag_s2 {
-
long l1;
-
long l2;
-
short s;
-
char c;
-
} s2;
-
Assuming sizeof long == 4 and sizeof short == 2 then
In s1
l1 needs to be 4 byte aligned so there will be 3 padding bytes following c. After l1 we are already 4 byte aligned so s can follow immediately but l2 needs to be 4 byte aligned so there will be 2 padding bytes following s. After l2 we are already 4 byte aligned so there is no need for any padding at the end of the structure.
sizeof(s1) = 16 bytes
In s2
l1 finishes on a 4 byte boundar so l2 can follow on immediately without any padding. l2 finishes on a 4 byte boundary so s can follow on immediately without any padding. c can follow immedately because generally you can put a single byte anywhere, after c we are at byte 11 so to get back to a 4 byte boundary 1 padding byte needs to be added at the end of the structure.
sizeof(s2) = 12 bytes
So s1 and s2 hold the same data but s2 does it in 4 less bytes. It is not uncommon in applications where memory is an issue to find structures ordered by the size of there members, largest to smallest, as this generally reduces the amount of memory required for a given structure.
I recently saved over 20k of memory in an embedded application by altering the order of members in a structure to save 12 bytes of padding. This structure was then declared in an array of 1800 items.