packed layout modifier improved

This commit improves the description of the packed type layout modifier.
pull/318/head
Philipp Schuster 3 years ago
parent 4993547527
commit c17dd174e5

@ -119,26 +119,65 @@ 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)` 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
`repr(packed(n))` can lower the alignment of every single struct member and thus
the alignment of the struct itself. The final alignment of each struct member is
`min(n, normal_alignment)`. Hence, `packed`/`packed(1)` aligns each field to a
one-byte boundary. Effectively, this strips any padding between member fields,
which may improve the memory footprint, but will likely have other negative
side-effects.
In particular, most architectures *strongly* prefer values to be aligned. This
may mean the 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.
may mean the 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.
[As this can cause undefined behavior][ub loads], the lint has been implemented.
With Rust 1.57 stable it is still a warning, but will become a hard error in the
future.
`repr(packed)` 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)`.
This repr is a modifier on `repr(C)` and `repr(Rust)`. A typical use case is
`repr(C, packed)`, which gives you full control over the exact type layout in
memory.
### Example
The example down below shows how you can mutate data in a packed struct and safely
handle unaligned pointers.
```rust
#[derive(Default)]
#[repr(packed)]
struct Foo {
a: u8,
b: u64,
}
impl Foo {
// safe way of creating an unaligned pointer to the field
fn b_mut_ptr(&mut self) -> *mut u64 {
core::ptr::addr_of_mut!(self.b)
}
}
fn main() {
println!("{:?}", {
let mut foo = Foo::default();
let ptr = foo.b_mut_ptr();
unsafe {
// safely write to the unaligned ptr
core::ptr::write_unaligned(ptr, *ptr + 1);
*ptr
}
});
}
```
## repr(align(n))
@ -150,7 +189,7 @@ 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)`.
`repr(packed)`, but a struct with `align(n)` can wrap a struct that is `packed`.
[unsafe code guidelines]: https://rust-lang.github.io/unsafe-code-guidelines/layout.html
[drop flags]: drop-flags.html

Loading…
Cancel
Save