Simple data types declared as variables are assigned addresses that are multiples of the size (in bytes) of the data type. Thus, variables of type long will be assigned addresses that are multiples of 4 (the bottom 2 bits of the address are 0).
Structures are padded so that each element of the structure will end up at a naturally aligned address. For example:
struct x_
{
char a; // 1 byte
int b; // 4 bytes
short c; // 2 bytes
char d; // 1 byte
} foo;
will actually be laid in memory so that it looks like this:
struct x_
{
char a; // 1 byte
char _pad0[3]; // padding to put 'b' on 4-byte boundary
int b; // 4 bytes
short c; // 2 bytes
char d; // 1 byte
char _pad1[1]; // padding to make sizeof(x_) multiple of 4
}
The result in both cases is that sizeof(struct x_)
will return 12. Note that char _pad0[3]
is included so that the int b
member will be on a 4-byte boundary. The reason char _pad1[1]
is included at the end is so that arrays of this structure will all have the same alignment; i.e.:
struct _x bar[3];
so that this array can be laid out as follows:
adr
offset element
------ -------
0x0000 char a; // bar[0]
0x0001 char pad0[3];
0x0004 int b;
0x0008 short c;
0x000a char d;
0x000b char _pad1[1];
0x000c char a; // bar[1]
0x000d char _pad0[3];
0x0010 int b;
0x0014 short c;
0x0016 char d;
0x0017 char _pad1[1];
0x0018 char a; // bar[2]
0x0019 char _pad0[3];
0x001c int b;
0x0020 short c;
0x0022 char d;
0x0023 char _pad1[1];
This is important so that each member of each array element can be accessed naturally.