| # Alternative representations |
| |
| Rust allows you to specify alternative data layout strategies from the default. |
| There's also the [unsafe code guidelines] (note that it's **NOT** normative). |
| |
| ## repr(C) |
| |
| This is the most important `repr`. It has fairly simple intent: do what C does. |
| The order, size, and alignment of fields is exactly what you would expect from C |
| or C++. The type is also passed across `extern "C"` function call boundaries the |
| same way C would pass the corresponding type. Any type you expect to pass through an FFI boundary should have |
| `repr(C)`, as C is the lingua-franca of the programming world. This is also |
| necessary to soundly do more elaborate tricks with data layout such as |
| reinterpreting values as a different type. |
| |
| We strongly recommend using [rust-bindgen] and/or [cbindgen] to manage your FFI |
| boundaries for you. The Rust team works closely with those projects to ensure |
| that they work robustly and are compatible with current and future guarantees |
| about type layouts and `repr`s. |
| |
| The interaction of `repr(C)` with Rust's more exotic data layout features must be |
| kept in mind. Due to its dual purpose as "for FFI" and "for layout control", |
| `repr(C)` can be applied to types that will be nonsensical or problematic if |
| passed through the FFI boundary. |
| |
| * ZSTs are still zero-sized, even though this is not a standard behavior in |
| C, and is explicitly contrary to the behavior of an empty type in C++, which |
| says they should still consume a byte of space. |
| |
| * DST pointers (wide pointers) and tuples are not a concept |
| in C, and as such are never FFI-safe. |
| |
| * Enums with fields also aren't a concept in C or C++, but a valid bridging |
| of the types [is defined][really-tagged]. |
| |
| * If `T` is an [FFI-safe non-nullable pointer |
| type](ffi.html#the-nullable-pointer-optimization), |
| `Option<T>` is guaranteed to have the same layout and ABI as `T` and is |
| therefore also FFI-safe. As of this writing, this covers `&`, `&mut`, |
| and function pointers, all of which can never be null. |
| |
| * Tuple structs are like structs with regards to `repr(C)`, as the only |
| difference from a struct is that the fields aren’t named. |
| |
| * `repr(C)` is equivalent to one of `repr(u*)` (see the next section) for |
| fieldless enums. The chosen size and sign is the default enum size and sign for the target platform's C |
| application binary interface (ABI). Note that enum representation in C is implementation |
| defined, so this is really a "best guess". In particular, this may be incorrect |
| when the C code of interest is compiled with certain flags. |
| |
| * Fieldless enums with `repr(C)` or `repr(u*)` still may not be set to an |
| integer value without a corresponding variant, even though this is |
| permitted behavior in C or C++. It is undefined behavior to (unsafely) |
| construct an instance of an enum that does not match one of its |
| variants. (This allows exhaustive matches to continue to be written and |
| compiled as normal.) |
| |
| ## repr(transparent) |
| |
| `#[repr(transparent)]` can only be used on a struct or single-variant enum that has a single non-zero-sized field (there may be additional zero-sized fields). |
| The effect is that the layout and ABI of the whole struct/enum is guaranteed to be the same as that one field. |
| |
| > NOTE: There's a `transparent_unions` nightly feature to apply `repr(transparent)` to unions, |
| > but it hasn't been stabilized due to design concerns. See the [tracking issue][issue-60405] for more details. |
| |
| The goal is to make it possible to transmute between the single field and the |
| struct/enum. An example of that is [`UnsafeCell`], which can be transmuted into |
| the type it wraps ([`UnsafeCell`] also uses the unstable [no_niche][no-niche-pull], |
| so its ABI is not actually guaranteed to be the same when nested in other types). |
| |
| Also, passing the struct/enum through FFI where the inner field type is expected on |
| the other side is guaranteed to work. In particular, this is necessary for |
| `struct Foo(f32)` or `enum Foo { Bar(f32) }` to always have the same ABI as `f32`. |
| |
| This repr is only considered part of the public ABI of a type if either the single |
| field is `pub`, or if its layout is documented in prose. Otherwise, the layout should |
| not be relied upon by other crates. |
| |
| More details are in the [RFC 1758][rfc-transparent] and the [RFC 2645][rfc-transparent-unions-enums]. |
| |
| ## repr(u*), repr(i*) |
| |
| These specify the size and sign to make a fieldless enum. If the discriminant overflows |
| the integer it has to fit in, it will produce a compile-time error. You can |
| manually ask Rust to allow this by setting the overflowing element to explicitly |
| be 0. However Rust will not allow you to create an enum where two variants have |
| the same discriminant. |
| |
| The term "fieldless enum" only means that the enum doesn't have data in any |
| of its variants. A fieldless enum without a `repr` is |
| still a Rust native type, and does not have a stable layout or representation. |
| Adding a `repr(u*)`/`repr(i*)` causes it to be treated exactly like the specified |
| integer type for layout purposes (except that the compiler will still exploit its |
| knowledge of "invalid" values at this type to optimize enum layout, such as when |
| this enum is wrapped in `Option`). Note that the function call ABI for these |
| types is still in general unspecified, except that across `extern "C"` calls they |
| are ABI-compatible with C enums of the same sign and size. |
| |
| If the enum has fields, the effect is similar to the effect of `repr(C)` |
| in that there is a defined layout of the type. This makes it possible to |
| pass the enum to C code, or access the type's raw representation and directly |
| manipulate its tag and fields. See [the RFC][really-tagged] for details. |
| |
| These `repr`s have no effect on a struct. |
| |
| Adding an explicit `repr(u*)`, `repr(i*)`, or `repr(C)` to an enum with fields suppresses the null-pointer optimization, like: |
| |
| ```rust |
| # use std::mem::size_of; |
| enum MyOption<T> { |
| Some(T), |
| None, |
| } |
| |
| #[repr(u8)] |
| enum MyReprOption<T> { |
| Some(T), |
| None, |
| } |
| |
| assert_eq!(8, size_of::<MyOption<&u16>>()); |
| assert_eq!(16, size_of::<MyReprOption<&u16>>()); |
| ``` |
| |
| This optimization still applies to fieldless enums with an explicit `repr(u*)`, `repr(i*)`, or `repr(C)`. |
| |
| ## repr(packed), repr(packed(n)) |
| |
| `repr(packed(n))` (where `n` is a power of two) forces the type to have an |
| alignment of *at most* `n`. Most commonly used without an explicit `n`, |
| `repr(packed)` is equivalent to `repr(packed(1))` which forces Rust to strip |
| any padding, and only align the type to a byte. This may improve the memory |
| footprint, but will likely have other negative side-effects. |
| |
| In particular, most architectures *strongly* prefer values to be naturally |
| aligned. This may mean that unaligned loads are penalized (x86), or even fault |
| (some ARM chips). For simple cases like directly loading or storing a packed |
| field, the compiler might be able to paper over alignment issues with shifts |
| and masks. However if you take a reference to a packed field, it's unlikely |
| that the compiler will be able to emit code to avoid an unaligned load. |
| |
| [As this can cause undefined behavior][ub loads], the lint has been implemented |
| and it will become a hard error. |
| |
| `repr(packed)/repr(packed(n))` is not to be used lightly. Unless you have |
| extreme requirements, this should not be used. |
| |
| This repr is a modifier on `repr(C)` and `repr(Rust)`. For FFI compatibility |
| you most likely always want to be explicit: `repr(C, packed)`. |
| |
| ## repr(align(n)) |
| |
| `repr(align(n))` (where `n` is a power of two) forces the type to have an |
| alignment of *at least* `n`. |
| |
| This enables several tricks, like making sure neighboring elements of an array |
| never share the same cache line with each other (which may speed up certain |
| kinds of concurrent code). |
| |
| This is a modifier on `repr(C)` and `repr(Rust)`. It is incompatible with |
| `repr(packed)`. |
| |
| [unsafe code guidelines]: https://rust-lang.github.io/unsafe-code-guidelines/layout.html |
| [drop flags]: drop-flags.html |
| [ub loads]: https://github.com/rust-lang/rust/issues/27060 |
| [issue-60405]: https://github.com/rust-lang/rust/issues/60405 |
| [`UnsafeCell`]: ../std/cell/struct.UnsafeCell.html |
| [rfc-transparent]: https://github.com/rust-lang/rfcs/blob/master/text/1758-repr-transparent.md |
| [rfc-transparent-unions-enums]: https://rust-lang.github.io/rfcs/2645-transparent-unions.html |
| [really-tagged]: https://github.com/rust-lang/rfcs/blob/master/text/2195-really-tagged-unions.md |
| [rust-bindgen]: https://rust-lang.github.io/rust-bindgen/ |
| [cbindgen]: https://github.com/eqrion/cbindgen |
| [no-niche-pull]: https://github.com/rust-lang/rust/pull/68491 |