> The structs are padded so that no padding occurs when we create an array of them,
> like with a scalar variable because if the compiler padded the struct when it created the
> array it wouldn't be the same behaviour we have when we created an array of integers.
> Is this notion correct?
not merely 'it wouldn't be the same behaviour we have when we created an array of integers'. array subscript and pointer arithmetic would not work otherwise.
> an anyone put it more formally?
the formal exposition is in the legalese in the IS (ISO/IEC 14882).
but this arises out of a few simple requirements:
1. the layout and sizeof an object of a particular compile-time type should be known at compile-time.
2. these have to be independent of the storage duration of the object.
3. these also have to be independent of whether the object is an element of an array, a member of a class, a base class sub-object etc.
4. object types can have alignment requirements.
5. an object should be allocated at an address that meets the alignment requirements of its object type.
6. array subscript and pointer arithmetic should work correctly.
7. the memory model of C++ should be compatible with that of C89.
here is a (poor) attempt at a formal explanation:
struct A
{
char a ;
int b ;
char c ;
};
the layout of A and sizeof(A) are known at compile-time and would be the same for all objects of type A, independent of the storage duration of the object. and independent of whether the object is an element of an array, a member of a class, a base class sub-object etc.
in an array, no padding can be added between elements of an array. required for pointer arithmetic (and array subscript) to work correctly.
... An object of array type contains a contiguously allocated non-empty set of N sub-objects of type T. ... IS 8.3.4/1
because of this, the sizeof(A) has to be an integral multiple of the alignof(A). and alignof(A) cannot be less than the alignof(any member of A).
for example, in an implementation where the sizeof(int) == 4 and the alignof(int) == 4, the alignof(A) == 4 and the layout of A could be
char a, 3 bytes padding, int b, char c, 3 bytes padding .
but not
char a, char c, 2 bytes padding, int b.
Nonstatic data members of a (non-union) class declared without an intervening access-specifier are allocated so that later members have higher addresses within a class object. ... IS 9.2/12
(required for C compatibility)
and not
3 bytes padding, char a, int b, char c, 3 bytes padding 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.
[Note: There might therefore be unnamed padding within a POD-struct object, but not at its beginning, as necessary to achieve appropriate alignment. ] IS 9.2/17
(also required for C compatibility)
struct B : A
{
char d ;
};
struct C
{
A a ;
char d ;
};
unless A is empty (and empty base class or empty member optimization applies), the padding at the end of A cannot be used to accommodate the member d.
The object representation of an object of type T is the sequence of N unsigned char objects taken up by the object of type T, where N equals sizeof(T). ...
[Footnote: The intent is that the memory model of C++ is compatible with that of ISO/IEC 9899 Programming Language C. --- end foonote] IS 3.9/4
Lippman in 'The C++ Object Model' explains it very well.