Skip to content

Commit fbb0bab

Browse files
committed
packed layout modifier improved
This commit improves the description of the packed type layout modifier.
1 parent 9493715 commit fbb0bab

File tree

1 file changed

+53
-13
lines changed

1 file changed

+53
-13
lines changed

src/other-reprs.md

+53-13
Original file line numberDiff line numberDiff line change
@@ -117,26 +117,65 @@ assert_eq!(16, size_of::<MyReprOption<&u16>>());
117117

118118
This optimization still applies to fieldless enums with an explicit `repr(u*)`, `repr(i*)`, or `repr(C)`.
119119

120-
## repr(packed)
120+
## repr(packed(n))
121121

122-
`repr(packed)` forces Rust to strip any padding, and only align the type to a
123-
byte. This may improve the memory footprint, but will likely have other negative
122+
`repr(packed(n))` can lower the alignment of every single struct member and thus
123+
the alignment of the struct itself. The final alignment of each struct member is
124+
`min(n, normal_alignment)`. Hence, `packed`/`packed(1)` aligns each field to a
125+
one-byte boundary. Effectively, this strips any padding between member fields,
126+
which may improve the memory footprint, but will likely have other negative
124127
side-effects.
125128

126-
In particular, most architectures *strongly* prefer values to be aligned. This
127-
may mean the unaligned loads are penalized (x86), or even fault (some ARM
128-
chips). For simple cases like directly loading or storing a packed field, the
129-
compiler might be able to paper over alignment issues with shifts and masks.
130-
However if you take a reference to a packed field, it's unlikely that the
131-
compiler will be able to emit code to avoid an unaligned load.
129+
In particular, most architectures *strongly* prefer values to be aligned. This
130+
may mean the unaligned loads are penalized (x86), or even fault (some ARM chips).
131+
For simple cases like directly loading or storing a packed field, the compiler
132+
might be able to paper over alignment issues with shifts and masks. However, if
133+
you take a reference to a packed field, it's unlikely that the compiler will be
134+
able to emit code to avoid an unaligned load.
132135

133-
[As this can cause undefined behavior][ub loads], the lint has been implemented
134-
and it will become a hard error.
136+
[As this can cause undefined behavior][ub loads], the lint has been implemented.
137+
With Rust 1.57 stable it is still a warning, but will become a hard error in the
138+
future.
135139

136140
`repr(packed)` is not to be used lightly. Unless you have extreme requirements,
137141
this should not be used.
138142

139-
This repr is a modifier on `repr(C)` and `repr(Rust)`.
143+
This repr is a modifier on `repr(C)` and `repr(Rust)`. A typical use case is
144+
`repr(C, packed)`, which gives you full control over the exact type layout in
145+
memory.
146+
147+
### Example
148+
149+
The example down below shows how you can mutate data in a packed struct and safely
150+
handle unaligned pointers.
151+
152+
```rust
153+
#[derive(Default)]
154+
#[repr(packed)]
155+
struct Foo {
156+
a: u8,
157+
b: u64,
158+
}
159+
160+
impl Foo {
161+
// safe way of creating an unaligned pointer to the field
162+
fn b_mut_ptr(&mut self) -> *mut u64 {
163+
core::ptr::addr_of_mut!(self.b)
164+
}
165+
}
166+
167+
fn main() {
168+
println!("{:?}", {
169+
let mut foo = Foo::default();
170+
let ptr = foo.b_mut_ptr();
171+
unsafe {
172+
// safely write to the unaligned ptr
173+
core::ptr::write_unaligned(ptr, *ptr + 1);
174+
*ptr
175+
}
176+
});
177+
}
178+
```
140179

141180
## repr(align(n))
142181

@@ -148,7 +187,8 @@ never share the same cache line with each other (which may speed up certain
148187
kinds of concurrent code).
149188

150189
This is a modifier on `repr(C)` and `repr(Rust)`. It is incompatible with
151-
`repr(packed)`.
190+
`repr(packed)`, but a struct with `align(n)` can wrap a struct, that is
191+
`packed`.
152192

153193
[unsafe code guidelines]: https://rust-lang.github.io/unsafe-code-guidelines/layout.html
154194
[drop flags]: drop-flags.html

0 commit comments

Comments
 (0)