Let's break that down:
"alignment rules" that "require the address of every primitive data element to be an even multiple of the element’s size". It's not very interesting that we're talking about alignment rules; we knew that already.
"require the address" of "every primitive data element" to be "an even multiple of the element’s size". Now we're getting somewhere. We have a requirement and a scope:
Requirement: The address is an even multiple of the element's size.
Scope: Every primitive data element.
So, every time we position an element, we must impose the requirement.
Let us try to position an element in memory. The first thing we will position is the short
labelled s
. Since a short takes up 2 bytes of memory, and we must make its address a multiple of that size, the address must be a multiple of 2. Let's call that address N.
So, s
takes up the space from N
up to N + 2
. (NOTE: For all of these ranges, the first endpoint is included, but the last endpoint is not. This is the normal way to describe ranges of integers in computer science; in most cases it is by far the most useful and least error-prone way to do it. Trust me.)
We continue with each other field.
c
takes up one byte, from N + 2
to N + 3
.
We are at N + 3
, but we cannot start t
there, because N + 3
is odd (since N
is even). So we must skip a byte. Thus t
ranges from N + 4
to N + 6
.
Continuing with this sort of logic, we end up with d
from N + 6
to N + 7
; r
from N + 8
to N + 16
; i
from N + 16
to N + 20
. (NOTE that this only works if we restrict N to be a multiple of 8, or r
will be unaligned. This is ok; when we allocate the memory for the array, we can align the start of it however we want - we just have to be consistent about the sequence of data after that point.)
So we need at least 20 bytes for this structure. (That's one of the advantages of the half-open ranges: the difference between the endpoints equals the size. If we included or excluded both endpoints from the range, we'd have to make a +1 or -1 correction.)
Now let's say we try to lay out the array as ten consecutive chunks of 20 bytes. Will this work? No; say that element 0 is at address 256 (a multiple of 8). Now r
in element 1 will be unaligned, because it will start at 256 + 20 + 8, which is not divisible by 8. That's not allowed.
So what do we do now? We can't just insert an extra 4 bytes before r
in element 1, because every element of the array must have the same layout (not to mention size). But there is a simple solution: we insert 4 bytes of additional padding at the end of each element. Now, as long as the array starts at some multiple of 8, every element will also start at a multiple of 8 (which, in turn, keeps r
aligned), because the size is now a multiple of 8.
We conclude that we need 24 bytes for the structure, and thus 24 * 10 = 240 bytes for the array.