From Optimizing Rust Struct Size:
So, here is how C lays out a struct. For each field in the order you defined them in the source:
- Determine the size and alignment of the field.
- Skip the number of bytes required from the end of the last field to meet the alignment of the next one.
- The field’s offset from the beginning is wherever you are now.
And, when you’re done with that, make the following two adjustments:
- The alignment of the struct is the alignment of the most-aligned field in it.
- The size of the struct gets rounded up to a multiple of the alignment. This makes arrays work, because we can find the nth array element with
n*sizeof(element).
This last step is unfortunate. It makes ((u16, u8), u8) for example take 6 bytes whereas it would otherwise take 4. (A tuple literally like this is not particularly useful, but imagine structs with similarly-size and similarly-aligned fields where the inner struct is a separate type because it is also used independently.)
What do you all think of making types having “two sizes”? One for how much space is needed to store a single value of this type (in a tuple/struct/enum, on the stack, …) and another for how much space (what offset) from an item to the next in an array or slice. The latter could be called “stride”, and only it would be rounded up. This would make the other size of (u16, u8) be 3 instead of 4, and ((u16, u8), u8) could then be 4 bytes.
One issue is what std::mem::size_of should return. It is used by unsafe code at least in the code for core::slice where it is assumed to be the stride. I don’t have an example in mind, but there could be other unsafe code that uses size_of and assumes it has the other meaning. (Perhaps copying raw bytes without using the typed std::ptr::{read, write} functions?) The code of libcore can be fixed whenever we change the language, but it an indication that other unsafe code outside of the standard library could be making the same assumption.
Perhaps we could deprecate size_of in favor of two other functions, pushing users to consciously choose one or the other. But that would be unfortunate, size_of is a nice name.