Rust 中的内存操作基于以下几个方法:
获取内存地址:
将 usize 转为 对象:
将地址转为 slice:
对于 Rc 而言,有两个相互搭配的函数:
在 Rust 文档中明确标注。使用 into_raw 之后如果不希望内存泄漏,则必须搭配 from_raw 使用。
需要注意的事项为:
Rust 中的胖指针。
unsized 引用可以被解引用。
下面是一些具体的例子:
拷贝 slice 数据
let mut buffer: [u8; 1024] = [0; 1024];
let data = v.as_slice();
let dest = std::ptr::addr_of_mut!(buffer) as *mut c_void;
let src = std::ptr::addr_of!(*data) as *const c_void; (1)
unsafe {
libc::memcpy(dest, src, data.len());
}
这里 data 的类型为 &u8,但是我们希望获得的是 [u8] 的地址,因此在这里进行解引用。
传递 dyn 对象
传递 dyn 对象以下要点:
dyn 对象的虚表地址储存在胖指针中。因此需要传递的实际上是胖指针的内容。
步骤如下:
创建 dyn 对象的胖指针。
将胖指针的内容储存到 buffer 中。
将 &buffer 强转为胖指针。
todo!()
内存拷贝
将指定值拷贝到指定内存一个常见方法是直接对指针类型强转后赋值:
unsafe { *(self.ptr as *mut T) = value };
但是 Rust 对内存地址有限制。变量的地址总是对齐的。因而很有可能出现下面的错误:
thread panicked at 'misaligned pointer dereference: address must be a multiple of 0x8 but is 0x16d359cbd'
要解决这种问题,需要使用 memcopy:
let pval = core::ptr::addr_of!(value) as *const u8;
unsafe { core::ptr::copy(pval, self.ptr, core::mem::sizeof::<T>()) };
这种拷贝会忽略大小端信息。因此还需要进行大小端转换:
*v = match self.ending {
BE => $id::from_be_bytes(unsafe { core::mem::transmute(*v) }),
LE => $id::from_le_bytes(unsafe { core::mem::transmute(*v) }),
};