The standard is fairly specific that even a POD-struct (which is, I believe the most restrictive class of structs) can have padding between members. ("There might therefore be unnamed padding within a POD-struct object, but not at its beginning, as necessary to achieve appropriate alignment." -- a non-normative note, but still makes the intent quite clear).
For example, contrast the requirements for a standard-layout struct (C++11, §1.8/4):
An object of trivially copyable or standard-layout type (3.9) shall occupy contiguous bytes of storage."
...with those for an array (§8.3.4/1):
An object of array type contains a contiguously allocated non-empty set of N subobjects of type T.
In the array, the elements themselves are required to be allocated contiguously, whereas in the struct, only the storage is required to be contiguous.
The third possibility that might make the "contiguous storage" requirement make more sense would be to consider a struct/class that is not trivially copyable or standard layout. In this case, it's possible that the storage might might not be contiguous at all. For example, an implementation might set aside one area of memory for holding all the private variables, and an entirely separate area of memory to hold all the public variables. To make that a little more concrete, consider two definitions like:
class A {
int a;
public:
int b;
} a;
class B {
int x;
public:
int y;
} b;
With these definitions, the memory might be laid out something like:
a.a;
b.x;
// ... somewhere else in memory entirely:
a.b;
b.y;
In this case, neither the elements nor the storage needs to be contiguous, so interleaving parts of entirely separate structs/classes is allowable.
That said, the first element must be at the same address as the struct as a whole (9.2/17): "A pointer to a POD-struct object, suitably converted using a reinterpret_cast, points to its initial member (or if that member is a bit-field, then to the unit in which it resides) and vice versa."
In your case, you have a POD-struct, so (§9.2/17): "A pointer to a POD-struct object, suitably converted using a reinterpret_cast, points to its initial member (or if that member is a bit-field, then to the unit in which it resides) and vice versa." Since the first member must be aligned, and the remaining members are all of the same type, it's impossible for any padding to be truly necessary between the other members (i.e., except for bit-fields, any type you can put in a struct you can also put in an array, where contiguous allocation of the elements is required). If you have elements smaller than a word, on a word-oriented machine (e.g., early DEC Alphas), it's possible that padding could make access somewhat simpler though. For example, early DEC Alphas (at the hardware level) were only capable of reading/writing an entirely (64-bit) word at a time. As such, let's consider something like a struct of four char
elements:
struct foo {
char a, b, c, d;
};
If it was required to lay these out in memory so they were contiguous, accessing a foo::b
(for example) would require that the CPU load the word, then shift it 8-bits right, then mask to zero-extend that byte to fill the entire register.
Storing would be even worse -- the CPU would have to load the current value of the whole word, mask out the current contents of the appropriate char-sized piece of that, shift the new value to the correct place, OR it into the word, and finally store the result.
By contrast, with padding between the elements, each of those becomes a simple load/store, with no shifting, masking, etc.
At least if memory serves, with DEC's normal compiler for the Alpha, int
was 32 bits, and long
was 64 bits (it predated long long
). As such, with your struct of four int
s, you could have expected to see another 32 bits of padding between the elements (and another 32 bits after the last element as well).
Given that you do have a POD-struct, you still have some possibilities though. The one I'd probably prefer would be to use offsetof
to get the offsets of the members of the struct, create an array of them, and access the members via those offsets. I showed how to do this in a couple of previous answers.