在 linux 上,该文件/var/run/utmp
包含几个utmp
结构,每个结构都是原始二进制格式,在一个文件中彼此跟随。utmp
本身是一个比较大的(在我的机器上是 384 字节)。我正在尝试将此文件读取为原始数据,并在数据有意义后实施检查。我对 rust 并不陌生,但这是我第一次真正体验到事物不安全的一面。
我有一个包含多个 c sturct utmp
s ( docs ) 的文件。在 rust 中,我想将整个文件读入一个Vec<libc::utmpx>
. 更具体地说,给定一个阅读器打开这个文件,我怎么能阅读一个struct utmp
?
以下是 的三种不同实现read_raw
,它们接受一个阅读器并返回一个RawEntry
(我的别名struct utmp
)。哪种方法最正确?我正在尝试编写尽可能高性能的代码,我担心read_raw0
如果涉及 memcpys 可能会比其他代码慢。完成此行为的最佳/最快方法是什么?
use std::io::Read;
use libc::utmpx as RawEntry;
const RawEntrySize = std::mem::size_of::<RawEntry>();
type RawEntryBuffer = [u8; RawEntrySize];
/// Read a raw utmpx struct
// After testing, this method doesn't work
pub fn read_raw0<R: Read>(reader: &mut R) -> RawEntry {
let mut entry: RawEntry = unsafe { std::mem::zeroed() };
unsafe {
let mut entry_buf = std::mem::transmute::<RawEntry, RawEntryBuffer>(entry);
reader.read_exact(&mut entry_buf[..]);
}
return entry;
}
/// Read a raw utmpx struct
pub fn read_raw1<R: Read>(reader: &mut R) -> RawEntry {
// Worried this could cause alignment issues, or maybe it's okay
// because transmute copies
let mut buffer: RawEntryBuffer = [0; RawEntrySize];
reader.read_exact(&mut buffer[..]);
let entry = unsafe {
std::mem::transmute::<RawEntryBuffer, RawEntry>(buffer)
};
return entry;
}
/// Read a raw utmpx struct
pub fn read_raw2<R: Read>(reader: &mut R) -> RawEntry {
let mut entry: RawEntry = unsafe { std::mem::zeroed() };
unsafe {
let entry_ptr = std::mem::transmute::<&mut RawEntry, *mut u8>(&mut entry);
let entry_slice = std::slice::from_raw_parts_mut(entry_ptr, RawEntrySize);
reader.read_exact(entry_slice);
}
return entry;
}
注意:经过更多测试,它似乎read_raw0
不起作用。我相信这是因为 transmute 创建了一个新缓冲区而不是引用结构。
这就是我想出的,我想它应该与读取单个条目一样快。它遵循您上一个条目的精神,但避免了转换(转换&mut T
为*mut u8
可以通过两次强制转换来完成:)t as *mut T as *mut u8
。此外,它使用MaybeUninit
而不是zeroed
更明确(程序集在优化后可能相同)。最后,无论哪种方式,该功能都是不安全的,因此我们不妨将其标记为这样并取消unsafe
块。
use std::io::{self, Read};
use std::slice::from_raw_parts_mut;
use std::mem::{MaybeUninit, size_of};
pub unsafe fn read_raw_struct<R: Read, T: Sized>(src: &mut R) -> io::Result<T> {
let mut buffer = MaybeUninit::uninit();
let buffer_slice = from_raw_parts_mut(buffer.as_mut_ptr() as *mut u8, size_of::<T>());
src.read_exact(buffer_slice)?;
Ok(buffer.assume_init())
}
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句