I need a clarification on Rust's representation in memory of register block structs (such as this one.
From the Rustnomicon, labelling a struct as repr(C) causes a memory layout where "The order, size, and alignment of fields is exactly what you would expect from C or C++".
My issue is that C (the language) does not precisely specify how a struct should be laid out in memory besides not having padding at the beginning and having the fields in the same order they are declared in. Is it assumed that it lays fields as they are conventionally expected to (aligned to data size, no padding if not necessary)?
The convention is not part of a standard, but is something all C compilers do and other languages like Rust rely on. Otherwise, there would be no interoperability. It is described in the Rust reference.
There are also edge cases, though, like for example disagreement about zero-sized structs. Overall, repr(C) should be understood, despite its name, as just “lay out using this specific algorithm we have documented”, which is often but not always compatible with C compilers.
Because of it being a specified, platform-independent[1] algorithm, which does not reorder fields, repr(C) is useful for many layout problems unrelated to C FFI. For example, it is often used to enable free type conversions;
is guaranteed to end up with the same layout as [f32; 3], making it sound to treat a &[Point] as an &[[f32; 3]] and vice versa. repr(C) or repr(C, packed) is also sometimes used as a foundation for interop with other layout systems (like GPU structs, which sometimes have unusual alignment requirements) by making use of repr(C)’s guarantee not to reorder fields, while inserting explicit dummy fields to match the padding expected by the other side. @Maldus512’s register block example can be seen as the same kind of thing, except that the other side is a unique thing rather than a case of some general struct layout algorithm.
except for the possibly platform-dependent size and alignment of the individual field types ↩︎
It's not quite true to say that it's not part of a standard; rather, it's not part of the ISO C Standard, but instead supplied by platform-specific ABIs.