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()
carey
August 6, 2020, 3:04am
2
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.
TomP
August 6, 2020, 3:08am
3
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?
TomP
August 6, 2020, 3:23am
5
"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
?
carey
August 6, 2020, 3:46am
7
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
system
Closed
November 4, 2020, 4:48am
9
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.