Memory Layout and Representation
Memory Layout Guarantees
Memory layout guarantees are the documented contracts in the Rust language specification that define when unsafe code, FFI bindings, and serialization routines can rely on a type's size, alignment, field offsets, and valid bit patterns. Relying on layout properties outside these guarantees is undefined behavior if a future compiler version or optimization pass changes the layout.
Complete Reference of Layout Guarantees
| Type or Construct | Guaranteed Size | Guaranteed Alignment | Additional Guarantees |
|---|---|---|---|
bool |
1 byte |
1 byte |
Bit pattern 0x00 is false, 0x01 is true |
u8 / i8, u16 / i16, u32 / i32, u64 / i64, u128 / i128 |
1, 2, 4, 8, 16 bytes |
Platform ABI (up to size) | Two's complement for signed integers; all bit patterns valid |
f32, f64 |
4, 8 bytes |
Platform ABI | IEEE 754 binary32 and binary64 formats |
char |
4 bytes |
Platform ABI (4 on major targets) |
Valid Unicode scalar value (0x0..=0xD7FF, 0xE000..=0x10FFFF) |
usize, isize |
Same as *const () |
Same as *const () |
Large enough to address any byte in memory |
&T, &mut T, Box<T>, NonNull<T> (where T: Sized) |
Same as *const T (1 word) |
Same as *const T |
Non-null and aligned; Option<Ptr> has the same layout as nullable *const T |
&[T], &mut [T], Box<[T]> |
2 * size_of::<usize>() |
align_of::<usize>() |
Contiguous len elements of T in memory (note: order of (ptr, len) inside the fat pointer itself is not guaranteed) |
[T; N] |
N * size_of::<T>() |
align_of::<T>() |
Contiguous elements at offsets i * size_of::<T>() with zero inter-element padding |
(), unit structs, [T; 0], PhantomData<T> |
0 bytes |
$\ge 1$ byte | Occupies no memory |
#[repr(transparent)] struct W(T) |
size_of::<T>() |
align_of::<T>() |
Identical layout, niches, and function-call ABI as T |
#[repr(C)] struct (with non-ZST fields) |
C ABI struct size | $\max(\text{align}(\text{fields}))$ | Sequential field offsets matching target C struct layout |
Option<T> where T is &U, &mut U, Box<U>, NonNull<U>, fn(), or NonZero* |
size_of::<T>() |
align_of::<T>() |
None is guaranteed to be encoded as all-zero bits (0) |
Array and Slice Layout Equivalence
An array [T; N] and a slice [T] of length N have identical contiguous element layouts in memory: element i always sits at byte offset i * size_of::<T>() from element 0. Because size_of::<T>() is already a multiple of align_of::<T>(), arrays and slices never insert extra padding between elements.
fn main() {
let matrix: [[u16; 3]; 2] = [[1, 2, 3], [4, 5, 6]];
// SAFETY: `[[T; M]; N]` is guaranteed to have the exact same contiguous memory
// layout as `[T; M * N]`.
let flat: &[u16; 6] = unsafe { &*(&matrix as *const [[u16; 3]; 2] as *const [u16; 6]) };
println!("matrix size: {} bytes", size_of_val(&matrix));
println!("flat array: {:?}", flat);
}
matrix size: 12 bytes
flat array: [1, 2, 3, 4, 5, 6]
Non-Guaranteed Layouts to Avoid Assuming
- Field order in default structs and tuples:
struct Pair(u32, u32)and(u32, u32)do not guarantee that.0sits at offset0and.1sits at offset4. Use[u32; 2]or#[repr(C)]when offset order is required. - Fat pointer field order: While
&[T]is16bytes on 64-bit platforms, the language does not guarantee whether the data pointer is the first word and length is the second word, or vice versa. Always extract components using.as_ptr()and.len(). - Standard library container headers:
Vec<T>,String,HashMap<K, V>,Rc<T>, andArc<T>are default-represented (#[repr(Rust)]) structs whose internal field order is an implementation detail and must never be transmuted across FFI.