I would certainly expect a double would have to be aligned on either a 32-bit word or 64-bit word boundary. But that will be processor and compiler dependant. You can test this by creating another data object BEFORE the struct, to shift its address, and see if the size changes.
An enum, I think, does not have a defined size, as it is, effectively, a compile-time constant. So, a good compiler will use the smallest data type capable of holding the maximum enum value, in this case a byte.
The compiler is not allowed to reorder the fields. You can potentially use that to your advantage to save some space. For example, putting two enum together in your definition allows the compiler to place them together in the layout. In your case, enum is byte-sized so they can be byte-aligned. Your example just has the one enum so this is only helpful for PID_Settings if you add another field that's 1, 2, or 4 bytes in size.
I cannot find any references one way or the other but I suspect the optimization level could affect layout.
As mentioned above, "packing" can make the structure smaller. Were I in your shoes I'd have two versions. One that's stored in EEPROM and the one you've shown us that's used by the running program. The EEPROM one would be packed to save space and include a revision number so the future me can fairly easily alter the layout. You'd need a bit of code to pack and unpack (copy the fields).
I'd be tempted to embed anything that might 'vary' in between the doubles, singly, though it's wasteful. May still not be foolproof, but if the compiler is busy aligning the doubles, chances are your size won't change. But hey, no compiler expert here.
Interesting question.
Does the same problem arise if we mix uint8_t, uint16_t and uint32_t variables in a struct? Will every compiler/version generate the same size of structure, or are those constructs still "at the compiler's discretion", and our EEPROM reads will be victim if we change? And, will the answer be different if we add 'packed' to our struct declarations?
you could have alignment decisions made based on the architecture. On a 8 bit UNO for example , you would not get any padding, but on a 32 bit ESP32 or MKR, the compiler might decide to align some members on a 32 bit boundary.
GCC offers the option to set some __attribute__ for the struct so you could do something like
Yup. That's what you'd have to do. I'm a bit paranoid so that motivates what I'd do. It's probably not be worth the effort.
I suggest using a CRC-32 instead of a one-byte sum. The CRC is guaranteed to fail on single bit errors and runs. It's my understanding those are the common EEPROM failures.
Exactly.
Compiler / version / platform / optimization level ... yes. The optimization level may not matter. The compiler definitely matters. The version doesn't matter very often.
With time, that becomes less of a problem. There are strong forces pushing towards specific struct layouts. But, if the compiler vendor does not provide a written guarantee, you cannot assume it's true.
Yes. Packing forces the compiler's hand. The tradeoff with using a packed structure is performance. The double in @Delta_G's structure are eight-byte aligned because that makes the processor go fast.
This conversation has moved along since I last read it. Has there been a definitive answer as to why the struct in @Delta_G's initial post reported a sizeof() of 56 bytes? I would have expected a maximum of 6 * 8 + 4 = 52, allowing 4 bytes for the enum.
I disagree, shouldn't need 8 bytes for the enum as it's the last element in the struct. The struct starts on a double word boundary for the first double, but doesn't have to end on one.
The compiler might "keep in mind" that you could have an array of such struct items and thus the size of the one item needs to be such that the next entry in the array would fall also on a x8 address
hence you get padding at the end may be or the attribute is at the very last byte and you had 7 byte of padding in front
I think the whole structure always will be aligned to 8bytes. But its exact size depend on type and the order of elements.
Interestingly, if we add an int field after the last enum - the size of struct remain the same? - (because enum and int will be packed in the same double-word cell. )
Or it will change, if the int and enum will require a separate cells?