Question
The C99 standard tells us:
There may be unnamed padding within a structure object, but not at its beginning.
and
There may be unnamed padding at the end of a structure or union.
I am assuming this applies to any of the C++ standards too, but I have not checked them.
Let's assume a C/C++ application (i.e. both languages are used in the application) running on an ARM Cortex-M would store some persistent data on a local medium (a serial NOR-flash chip for instance), and read it back after power cycling, possibly after an upgrade of the application itself in the future. The upgraded application may have been compiled with an upgraded compiler (we assume gcc).
Let's further assume that the developer is lazy (that's not me, of course), and directly streams some plain C or C++ structs to flash, instead of first serializing them as any paranoid experienced developer would do.
In fact, the developer in question is lazy, but not totally ignorant, since he has read the AAPCS (Procedure Call Standard for the Arm Architecture).
His rationale, besides laziness, is the following:
- He does not want to pack the
structs to avoid misalignment problems in the rest of the application. - The AAPCS specifies a fixed alignment for every single fundamental data type.
- The only rational motivation for padding is to achieve proper alignment.
- Therefore, he thinks, padding (and therefore member
offsetofand totalsizeof) is fully determined for any C or C++structby the AAPCS. - Therefore, he further reasons, there is no way my application would not be able to interpret some read back data that an earlier version of the same application would have written (assuming, of course, that the offset of the data in flash memory has not changed between writing and reading).
However, the developer has a conscience and he is a little worried:
- The C standard does not mention any reason for padding. Achieving proper alignment may be the only rational reason for padding, but compilers are free to pad as much as they want, according to the standard.
- How can he be sure that his compiler really follows the AAPCS?
- Could his assumptions suddenly be broken by some apparently unrelated compiler flag that he would start using, or by a compiler upgrade?
My question is: how dangerously does that lazy developer live? In other words, how stable is padding in C/C++ structs under the assumptions above?
Conclusion
Two weeks after this question was asked, the only answer that has been received does not really answer the asked question. I have also asked the exact same question on an ARM community forum, but got no answer at all.
I however choose to accept 3246135 as the answer because:
I take the absence of proper answer as very relevant information for this case. The correctness of solutions to software problems should be obvious. The assumptions made in my question may be true, but I cannot easily prove it. Additionally, if the assumptions are incorrect, the consequences, in the general case, could be catastrophic.
Compared to the risk, the burden on the developer when using the strategy exposed in the answer seems very reasonable. Assuming a constant endianness (which is quite easy to enforce), it is a hundred percent-safe (any deviation will generate an error at compile-time) and it is much lighter than a full-blown serialization. Basically, the strategy exposed in the answer is a mandatory minimum price to pay in order to make one's C/C++
structs persistent independently of any ABI.
If you are a developer asking yourself the question above, please do not be lazy, and use instead the strategy exposed in the accepted answer, or an alternative strategy that guarantees a constant padding across software releases.