我有一个看起来像这样的结构:
#[repr(packed)]
struct Header {
some: u8,
thing: u8,
}
如何从中获取原始字节,我可以用于C库或套接字交互?
我希望使用transmute
来解决问题,但不幸的是,这不起作用:
let header = Header {....}
let header_bytes: &[u8] = unsafe { mem::transmute(header) };
let result = self.socket.write(header_bytes);
失败
error: transmute called on types with different sizes: &Header (64 bits) to &[u8] (128 bits)
答案 0 :(得分:7)
编辑。
你不能将任意事物转化为任意事物(例如Header
到&[u8]
)因为transmute()
类似于C ++中的reinterpret_cast
:它实际上重新解释了其参数包含的字节,为了使其成功,源和目标类型应具有相同的大小。但即使Header
和&[u8]
具有相同的大小,在它们之间进行转换也没有意义:Header
是实际值,而&[u8]
是指针在指针后面有一个数据大小。
为了将一段数据解释为一个字节切片,您需要执行三个步骤:获取指向数据的原始指针,将其转换为指向u8
的指针,然后将其转换为切片u8
。这意味着使用长度增强原始指针值,在这种情况下,长度等于结构大小。最后一步可以使用std::slice::from_raw_parts()
轻松完成:
use std::slice;
use std::mem;
let p: *const Header = &header; // the same operator is used as with references
let p: *const u8 = p as *const u8; // convert between pointer types
let s: &[u8] = unsafe {
slice::from_raw_parts(p, mem::size_of::<Header>())
};
然而,在大多数情况下这样做并不是一个好主意。即使结构被标记为打包,它仍然存在字节顺序的问题,所以至少执行此操作的代码不会是可移植的(或者更确切地说,它以这种形式序列化的数据可能不是可以通过为另一个架构编译的相同程序恢复。)
答案 1 :(得分:0)
您可以使用如下函数将任何对象转换为字节切片:
/// Safe to use with any wholly initialized memory `ptr`
unsafe fn raw_byte_repr<'a, T>(ptr: &'a T) -> &'a [u8]
{
std::mem::transmute(std::raw::Slice{
data: ptr as *const _ as *const u8,
len: std::mem::size_of::<T>(),
})
}
我不知道完整的安全性分析,但只要你不访问任何uninit值就应该没问题。