On Fri, May 15, 2020 at 1:45 PM Philippe Verdy <verdyp@gmail.com> wrote:
> if alignment is needed and used by the compiler for its own performance goals (and measurable in "bytes" with "sizeof") it is only with *prepadding* before the type, no type is followed by trailing padding bytes.
That "prepadding" is, IMNSHO, an invention of yours.
No, "prepadding" is what happens to align a new added field to respect its alignment contraint (i.e. determining its starting offset). "postpadding" is never needed anywhere for any type (independantly of their alignment constraint or usable size).
What you append a char[], or char[0] or char[1] or char[n], the first item in the array will be at the same starting offset (measured in bytes) which only depends on the alignemnt constraint of the type itself but not on what could follow it in the structure.
So there's never any *appended* padding (except trailing bits after bitfields, just what is needed to fit the byte boundaries of the structure).
Give me only one example where the absence of presence of a char[0] field at end of a structure can change its sizeof() or alignof() properties: I've never seen any such platform. Note that even if there's no trailing padding in, the type itself, it may occur if you create an array of such structures, independantly of the presence of absence of a char[0], but only because of the alignof() property required by the first field in the structure.
Suppose you have on a 32-bit platform with strict alignment required for the 32-bit "int":
struct f1 { int a; char b; }
then its sizeof should still be 5, its alignof should be 4. But an array of struct f1 will need not 5 bytes per item, but 8 bytes due to the alignof property (so there will be 3 bytes added between structures and optionally after the last item but this is not required). suppose you want to allocate an array of 10 such structures, it should allocate 77 bytes (or 80 if there are trailing bytes after the last item but it is not needed), not 50 and you need to perform calloc(10,8) by first rounding up the sizeof from 5 to 8 to respect the alignment for all items (not just the first one). But such trailing padding of "struct f1" is not required at all in:
struct f2 {struct f1; char c;}
whose size of is now 6 (not 9), its alignof is still 4. And an array of f2 will still need 8 bytes per item with two required bytes between items. Now with
struct f3 {struct f1; char c,d,e;}
you have a sizeof equal to 8, its alignof is still 4, and an array of f3 will not need any padding anywhere between items.
In all cases, you never need any trailing padding.
If you think that struct f1 should have sizeof 8, then this is not efficient: you always waste 3 bytes of unnecessary padding which is not needed for correct alignement of its defined fields. It simplifies the life of programmers (that want to care about alignment, just about sizeof).
In old C, there was only sizeof() documented (and legacy memory allocators like malloc/calloc did not care about alignment constraints) so old compilers were forced to add trailing padding bytes so that the sizeof() is a multiple of the alignof() internal property of the type, in such case:
struct f1 { int a; char b; }
would have a sizeof set to 8, not 5, to repect the 4-byte alignemtn for the first field, which is needed only to create an array of such structures.
Compilers have evolved, and allow programmers to control if they want such waste: there are compiler compiling options, or pragma directives inserted to surround some sections of code, or platform-specific declarators. And various memory allocation APIs now support specifying not just the desired size, but also a parameter for the desired alignment (in that case, don't use only sizeof(type) with malloc/calloc without first rounding up the size and even allocate more bytes to make sure that you get a pointer that you can offset to the desired alignment: if your alignment constraint is 4, you need to allocate 3 additional bytes in all cases, if you use legacy malloc/calloc calls). If you're allocating the array in C++ with "new type[count]", the compiler will make the adjustment itself as it knows the alignemnt contraint for the indicated base type.