gpt4 book ai didi

serialization - 如何在没有 old_io 的情况下从字节读取/写入整数值?

转载 作者:行者123 更新时间:2023-11-29 07:55:44 24 4
gpt4 key购买 nike

std::old_io 模块中有方便的特征 ReaderWriter 可以使用各种字节顺序读取/写入整数值。但是该模块被声明为已过时,所以我正在尝试找出其他方法来做到这一点。

一种方法是读取字节并用位运算构造结果值。标准库中还有其他方法吗?例如。从 &[u8] 中读取 u64,它以大端编码方式进行编码。我会在 C 中做的是将 uint8_t 数组中的 8 个字节 memcpy 到 uint64_t 值,然后执行类似 htons 的操作来交换字节,如果必要的。

最佳答案

将整数值转换为数组/切片非常容易,可用于写入文件流,就像您上面所说的使用位运算一样。但是,我想在这里发布,以便人们理解使用位方法(就像我在下面所做的和已经提到的原始海报)实际上至少优化了 X86_64 上的单个指令。这与执行原始发布者所说的 memcpy 操作完全相同。

例如,看一下这段代码:

#[inline]
fn u16tou8ale(v: u16) -> [u8; 2] {
[
v as u8,
(v >> 8) as u8,
]
}

// little endian
#[inline]
fn u32tou8ale(v: u32) -> [u8; 4] {
[
v as u8,
(v >> 8) as u8,
(v >> 16) as u8,
(v >> 24) as u8,
]
}

// big endian
#[inline]
fn u32tou8abe(v: u32) -> [u8; 4] {
[
(v >> 24) as u8,
(v >> 16) as u8,
(v >> 8) as u8,
v as u8,
]
}

fn main() {
println!("{:?}", u32tou8ale(0x12345678));
println!("{:?}", u32tou8abe(0x12345678));
}

函数 u32tou8ale 例如,实际上变成了 CPU 执行的单个指令。这条指令创建了 [u8; 4] 堆栈上的数组,即使是大端版本 u32tou8abe 也是创建 [u8; 4]。这是可能的,因为优化器。你可能会说这是因为它是一个常量编译时间值,但如果你试验你会发现,当给定一个编译器无法提前知道的 u32 值时,它仍然会在堆栈中一次性生成数组本质上是通过执行内存复制操作来执行指令。例如:

fn main() {
unsafe {
let p: *const u32 = std::mem::transmute(main);
println!("{:?}", u32tou8ale(*p));
}
}

这从符号 main 引用的内存位置读取一个值,这是我们的函数。编译器不知道这个值,因此它发出一条移动指令,将该值读入堆栈,然后它认为该值是一个 [u8; 4]

至于可移植性,只需始终明确说明您读取和写入值的字节顺序,一切都会正常进行。例如,如果你使用 u32tou8ale 那么无论你的目标是什么架构,你都会得到小字节顺序,如果你写了等效的读取函数并且你明确地读取大字节顺序那么你可以肯定你会阅读该顺序。

我希望这对来到这里寻求将整数转换为字节并从中转换的人有所帮助!

关于serialization - 如何在没有 old_io 的情况下从字节读取/写入整数值?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29206540/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com