Casting pointer of struct, reinterpret_cast in c++

I would like to cast a pointer of a field in struct T to struct U, how can I do it.

given the following struct

struct Page {
    data: [u8; 4096]
}

struct Block {
   a: u32
   b: u32
}

impl Block {
   fn set_a()
   fn get_a()
}

I would like to get first 8 bytes of Page.data, and split them in [u8; 4], [u8; 4] and get the new Block with something like from_be_bytes.

However, dealing with fixed size array is not that straightforward
Do I need MaybeUnit or complete them with raw pointer ?
I am really confusing.

something like this in c++

char *GetData() { return data; }

auto block = reinterpret_cast<Block *>(page->GetData());
block->set_a()
block->get_a()

The safe way to do this would be to clone_from_slice into an array, then use from_ne_bytes on that:

let mut a: [u8; 4] = [0; 4];
a.clone_from_slice(&data[0..=3]);
let mut b: [u8; 4] = [0; 4];
b.clone_from_slice(&data[4..=7]);
Block { a: u32::from_ne_bytes(a), b: u32::from_ne_bytes(b) }

One unsafe way to do it like C++ would use std::mem::transmute_copy. That won’t necessarily get you any better code after optimisation than the safe code, though.

Note that the change from from_be_bytes() to from_ne_bytes() converts the code from malfunctioning on little-endian machines to functioning on all architectures.

Why is that? Aren't they just the reverse order to save bytes?

"be" is "big endian" (i.e., older IBM processors and standard network transmission order for most internationally-standardized protocols).

"ne" is "native endian", which is little endian for Intel processors and most ARM processors.

3 Likes

It seems that this method is copy the data from Page.data and then we need to copy back the Page.data.

Will this copy method slower than modify raw pointer directly? If is, how can I cast the raw pointers and modify it safely

Or the only way is std::mem::transmute_copy?

It does copy it out. Depending on what you’re doing with it, it might not copy it further than a CPU register, which wouldn't really be slow.

You can’t modify aliased memory like that directly in Rust without using unsafe at some point.

1 Like

Moreover, if there is any "live" shared reference to this memory, it must not be modified at all, even through unsafe. Exception - &UnsafeCell<T> allows for changes of T (but not of UnsafeCell itself).

2 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.