转换 Vec u32 ;到 Vec u8 ;就地和最小的开销 [英] Converting a Vec<u32> to Vec<u8> in-place and with minimal overhead

查看:36
本文介绍了转换 Vec u32 ;到 Vec u8 ;就地和最小的开销的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试将 u32Vec 转换为 u8Vec,最好是就地,没有太多的开销.

I'm trying to convert a Vec of u32s to a Vec of u8s, preferably in-place and without too much overhead.

我当前的解决方案依赖于不安全的代码来重新构建Vec.有没有更好的方法来做到这一点,我的解决方案有哪些风险?

My current solution relies on unsafe code to re-construct the Vec. Is there a better way to do this, and what are the risks associated with my solution?

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)
}

Rust Playground 链接

推荐答案

  1. 每当编写不安全块时,我强烈鼓励人们在块上添加注释,解释为什么您认为代码实际上是安全的.这类信息对以后阅读代码的人很有用.

  1. Whenever writing an unsafe block, I strongly encourage people to include a comment on the block explaining why you think the code is actually safe. That type of information is useful for the people who read the code in the future.

不要添加关于幻数"4的评论,只需使用mem::size_of::.我什至会为 u8 使用 size_of 并执行除法以获得最大清晰度.

Instead of adding comments about the "magic number" 4, just use mem::size_of::<u32>. I'd even go so far as to use size_of for u8 and perform the division for maximum clarity.

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

You can return the newly-created Vec from the unsafe block.

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

As mentioned in the comments, "dumping" a block of data like this makes the data format platform dependent; you will get different answers on little endian and big endian systems. This can lead to massive debugging headaches in the future. File formats either encode the platform endianness into the file (making the reader's job harder) or only write a specific endinanness to the file (making the writer's job harder).

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

I'd probably move the whole unsafe block to a function and give it a name, just for organization purposes.

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

You don't need to import Vec, it's in the prelude.

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)
}

游乐场

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

My biggest unknown worry about this code lies in the alignment of the memory associated with the Vec.

Rust 的底层分配器 分配释放内存与一个特定的Layout.Layout 包含指针的大小对齐等信息.

Rust's underlying allocator allocates and deallocates memory with a specific Layout. Layout contains such information as the size and alignment of the pointer.

我假设这段代码需要 Layout 来匹配对 allocdealloc 的成对调用.如果是这种情况,删除VecVec 构造而成,可能会告诉分配器错误的对齐方式,因为该信息是 基于元素类型.

I'd assume that this code needs the Layout to match between paired calls to alloc and dealloc. If that's the case, dropping the Vec<u8> constructed from a Vec<u32> might tell the allocator the wrong alignment since that information is based on the element type.

如果没有更好的知识,最好"的做法是保持 Vec 原样,只需获取一个 &[u8]它.切片与分配器没有交互,避免了这个问题.

Without better knowledge, the "best" thing to do would be to leave the Vec<u32> as-is and simply get a &[u8] to it. The slice has no interaction with the allocator, avoiding this problem.

即使不与分配器交互,您也需要注意对齐!

Even without interacting with the allocator, you need to be careful about alignment!

另见:

这篇关于转换 Vec u32 ;到 Vec u8 ;就地和最小的开销的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆