Serialization 从压缩结构获取原始字节

Serialization 从压缩结构获取原始字节,serialization,rust,Serialization,Rust,我有一个结构,看起来像这样: #[repr(packed)] struct Header { some: u8, thing: u8, } /// 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{

我有一个结构,看起来像这样:

#[repr(packed)]
struct Header {
    some: u8,
    thing: u8,
}
/// 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>(),
    })
}
如何从中获取原始字节,用于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)

您可以使用如下函数将任何对象生成字节片:

#[repr(packed)]
struct Header {
    some: u8,
    thing: u8,
}
/// 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>(),
    })
}
///可与任何完全初始化的内存一起安全使用`ptr`
不安全fn原始字节报告和'a[u8]
{
std::mem::transmute(std::raw::Slice{
数据:ptr为*常数uu为*常数u8,
len:std::mem::size_of::(),
})
}


我不知道完整的安全性分析,但只要您不访问任何uninit值,就应该可以了。

编辑:更新了Rust 1.x

您不能将任意事物转换为任意事物(如
和[u8]
),因为
转换()
类似于C++中的
重新解释\u cast
:它字面上重新解释其参数所包含的字节,为了成功,源类型和目标类型应该具有相同的大小。但是,即使
标题
&[u8]
具有相同的大小,在它们之间进行转换也没有意义:
标题
是一个实际值,而
&[u8]
是一个指针,指针后面有一个数据大小

为了将一段数据解释为字节片,您需要执行三个步骤:获取指向数据的原始指针,将其转换为指向
u8
的指针,然后将其转换为
u8
的片。这意味着使用长度增强原始指针值,在本例中,长度等于结构大小。最后一步可以通过以下方法轻松完成:

使用std::slice;
使用std::mem;
设p:*const Header=&Header;//与引用使用相同的运算符
设p:*常数u8=p为*常数u8;//在指针类型之间转换
设s:&[u8]=不安全{
切片::来自原始零件(p,mem::大小::())
};

然而,在大多数情况下这样做并不是一个好主意。即使结构被标记为压缩,它仍然会留下字节顺序的问题,因此至少这样做的代码不会是可移植的(或者更确切地说,它以这种形式序列化的数据可能无法由为另一个体系结构编译的同一个程序恢复)。

您知道现在应该如何做吗?检查文档时发现
std::slice::raw::buf_as_slice
已被弃用,但没有提供任何替代方案。@HarveyAdcock,我已更新了最新版本的答案。在稳定语言中,从原始指针获取切片的首选方法是
std::slice::from_raw_parts()
。感谢您的更新。如果这不是一个好主意,那么如果我试图将一个结构从堆栈复制到内存中一个更永久的受管理部分,您会建议采用什么其他方法?我正在制作一个简单的内存分配器,所以我想我必须像这样处理复制字节的问题。@HarveyAdcock如果你在自己的进程中这样做的话,我认为这种方法很好。此评论主要针对通过网络传输数据或将其存储在外部某处。在后一种情况下,最好使用具体的序列化格式,如JSON。