How to write & read a vec of struct with unaligned fields?

⚓ Rust    📅 2025-09-21    👤 surdeus    👁️ 7      

surdeus

Warning

This post was published 40 days ago. The information described in this article may have changed.

This is a continuation of this thread. I have a struct like this:

struct MyStruct {
	other_items_offset: u32,
	foo: u32,
	bar: u8,
	baz: u8
}

It's not 32- or 64-bit aligned, I know. I just created it this way to see it with the smallest possible fields.

And I have a vector of them (about 100K items), that I want to save into a file, and then in another Rust binary in the same project, I want to read them into a vector (not mem-map, because I want to resize the vector, and for now it's just too complicated for me).

I tried to write it with Zerocopy. If a struct has just several u64's, everything is fine. But with this one, the approach won't work.

The derive macros don't work:

use zerocopy::{FromBytes, IntoBytes, Immutable};

#[derive(Debug, FromBytes, IntoBytes, Immutable)]
                           ^^^^^^^^^
`graph::VertexData` has inter-field padding
consider using `zerocopy::Unalign` to lower the alignment of individual fields
consider adding explicit fields where padding would be
consider using `#[repr(packed)]` to remove inter-field padding
the trait `PaddingFree<graph::VertexData, true>` is not implemented for `()`
but trait `PaddingFree<graph::VertexData, false>` is implemented for it
see issue #48214

I add #[repr(packed)] and then my test cases fail:

data_vec.iter().enumerate().for_each(|(i, v)| println!("rec {}, {}", i, v.other_items_offset));
                                                                        ^^^^^^^^^^^^^^^^^^^^
reference to packed field is unaligned
packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses
creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)

What can I do to pack it and unpack into binary files?

I could, of course, write my own pack/unpack routine, but I hope there's a better way.

4 posts - 3 participants

Read full topic

🏷️ Rust_feed