rust 从压缩结构中获取原始字节

kqqjbcuj  于 2023-05-29  发布在  其他
关注(0)|答案(2)|浏览(173)

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

#[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)
mnemlml8

mnemlml81#

**编辑:**针对Rust 1.x更新。

你不能把任意的东西转换成任意的东西(比如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>())
};

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

w46czmvw

w46czmvw2#

你可以使用如下函数将任何对象变成字节切片:

/// 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>(),
    })
}

Run in Rust playpen.
我不知道完整的安全分析,但只要你不访问任何uninit值,它应该是好的。

相关问题