Clarification repr(C) for register blocks

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)?

1 Like

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.

2 Likes

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;

#[repr(C)]
struct Point {
   x: f32,
   y: f32,
   z: f32,
}

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.


  1. except for the possibly platform-dependent size and alignment of the individual field types ↩︎

3 Likes

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.

For example, the x86-64 psABI for ELF systems precisely describes it for ELF platforms like Linux on x86-64 CPUs, while there's a similar document for the Windows x64 ABI.

Of course, these documents can have errors and omissions, like all specifications, but they do cover most things correctly.

2 Likes

See also repr(C) does not always match the current target's C toolchain (when that target is windows-msvc) · Issue #521 · rust-lang/unsafe-code-guidelines · GitHub (for windows msvc in particular).

2 Likes