将Vec <u32>转换为Vec <u8>,并且开销最小

Tho*_*ers 4 casting unsafe rust

我想一个转换Vecu32s到一个Vecu8S,最好就地并没有太多的开销.

我目前的解决方案依赖于不安全的代码来重新构建Vec.有没有更好的方法来做到这一点,以及与我的解决方案相关的风险是什么?

use std::mem;
use std::vec::Vec;

fn main() {
    let mut vec32 = vec![1u32, 2];
    let vec8;
    unsafe {
        let length = vec32.len() * 4; // size of u8 = 4 * size of u32
        let capacity = vec32.capacity() * 4; // ^
        let mutptr = vec32.as_mut_ptr() as *mut u8;
        mem::forget(vec32); // don't run the destructor for vec32

        // construct new vec
        vec8 = Vec::from_raw_parts(mutptr, length, capacity);
    }

    println!("{:?}", vec8)
}
Run Code Online (Sandbox Code Playgroud)

Rust Playground链接

She*_*ter 8

  1. 每当写一个unsafe块时,我强烈建议人们在块上添加注释,解释为什么你认为代码实际上是安全的.这种类型的信息对将来阅读代码的人很有用.

  2. 只需使用,而不是添加关于"幻数"4的评论mem::size_of::<u32>.我甚至会去那么远,使用size_ofu8和执行部门的最大清晰.

  3. 您可以从unsafe块中返回新创建的Vec .

  4. 正如评论中所提到的,"倾销"这样的数据块会使数据格式平台依赖 ; 你将在小端和大端系统上得到不同的答案.这可能导致未来的大量调试问题.文件格式要么将平台字节序编码到文件中(使读者的工作更难),要么只对文件写一个特定的endinanness(使作者的工作更难).

  5. 我可能unsafe会将整个块移动到一个函数并为其命名,仅用于组织目的.

  6. 你不需要导入Vec,它在前奏中.

use std::mem;

fn main() {
    let mut vec32 = vec![1u32, 2];

    // I copy-pasted this code from StackOverflow without reading the answer 
    // surrounding it that told me to write a comment explaining why this code 
    // is actually safe for my own use case.
    let vec8 = unsafe {
        let ratio = mem::size_of::<u32>() / mem::size_of::<u8>();

        let length = vec32.len() * ratio;
        let capacity = vec32.capacity() * ratio;
        let ptr = vec32.as_mut_ptr() as *mut u8;

        // Don't run the destructor for vec32
        mem::forget(vec32);

        // Construct new Vec
        Vec::from_raw_parts(ptr, length, capacity)
    };

    println!("{:?}", vec8)
}
Run Code Online (Sandbox Code Playgroud)

操场

我对此代码最大的未知担忧在于与内存关联的内存对齐Vec.

Rust的底层分配器使用特定的分配释放内存.包含诸如指针的大小对齐之类的信息.LayoutLayout

我认为这个代码需要Layout以成对调用之间的匹配allocdealloc.如果是这种情况,那么Vec<u8>从a中删除构造Vec<u32>可能会告诉分配器错误的对齐,因为该信息基于元素类型.

如果没有更好的知识,那么"最好的"事情就是离开现状Vec<u32>并简单地得到&[u8]它.切片与分配器没有交互,避免了这个问题.

也可以看看:

  • 我没有怀疑过“布局”的问题。在低级代码中,我习惯于担心转换为具有*更大*对齐的指针,但转换为具有*较低*对齐的指针始终是安全的。我想知道是否应该指定分配器应该优雅地处理这种情况。 (2认同)

att*_*ona 5

如果就地转换不是那么强制性的,这样的东西管理字节顺序控制并避免不安全块:

extern crate byteorder;

use byteorder::{WriteBytesExt, BigEndian};

fn main() {
    let vec32: Vec<u32> = vec![0xaabbccdd, 2];
    let mut vec8: Vec<u8> = vec![];

    for elem in vec32 {
        vec8.write_u32::<BigEndian>(elem).unwrap();
    }

    println!("{:?}", vec8);
}
Run Code Online (Sandbox Code Playgroud)

  • 编译器的优化(使用“-O3”)会使整个 for 循环成为无操作吗? (2认同)