当前位置: 首页 > 知识库问答 >
问题:

Rust:数组长度的宏

郝承悦
2023-03-14

我有一个包含原始二进制数据的文件,我想把它加载到一个4字节长的u32字数组中。

可以通过在编译时包含文件的内容来执行

let bytes = include_bytes!("audio.raw");

然后,我可以使用transmute将其转换为u32字的数组。新数组的长度显然应该是原始字节数组的1/4。

let audio = unsafe { std::mem::transmute::<[u8; 63504], [u32; 15876]>(*bytes) };
// works

正如你在上面看到的,我必须对输入和输出数组的长度进行硬编码。然而,当试图避免硬编码这些数字时,它不起作用:

let audio = unsafe { std::mem::transmute::<[u8; bytes.len()], [u32; bytes.len()/4]>(*bytes) };
// error: non-constant value

似乎。len()在运行时被调用,由于在Rust中无法分配动态数组,因此会产生错误。然而,理论上,应该有一种方法来计算编译阶段所需的长度,因为字节数组的长度是固定的。所以我的问题是:是否有一个宏返回静态数组的长度?

(我非常清楚向量可以进行动态分配,我的问题是关于固定大小的数组。)

示例代码(include_bytes替换为硬编码数组):

fn main() {
    // let bytes = include_bytes!("audio.raw");
    let bytes = [1, 0, 0, 0, 2, 0, 0, 0];

    // works:
    let audio = unsafe { std::mem::transmute::<[u8; 8], [u32; 2]>(bytes) };

    // error:
    let audio = unsafe { std::mem::transmute::<[u8; bytes.len()], [u32; bytes.len() / 4]>(bytes) };

    println!("{}", audio[1]);
}

共有2个答案

刘玉石
2023-03-14

array实现Deref

为了获得一个表示数组长度的常量值,trait助手可能会满足您的需要。

稳定的:

trait ArrayLen {
    const SIZE: usize;
}

macro_rules! impl_array(
    ($($size:expr),+) => {
        $(
            impl<'a, T> ArrayLen for &'a [T; $size] {
                const SIZE: usize = $size;
            }
        )+
    }
);

impl_array!(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 20, 24, 32, 36,
            0x40, 0x80, 0x100, 0x200, 0x400, 0x800, 0x1000, 0x2000, 0x4000, 0x8000,
            0x10000, 0x20000, 0x40000, 0x80000, 0x100000);

fn print<T>(_: T)
where
    T: ArrayLen
{
    println!("{}", T::SIZE);
}

fn main() {
    let bytes = include_bytes!("four_bytes_file.something");
    // The length of `bytes` must match one of the implementations
    print(bytes);
}

每晚:

#![feature(const_generics)]

trait ArrayLen {
    const SIZE: usize;
}

impl<'a, T, const N: usize> ArrayLen for &'a [T; N] {
    const SIZE: usize = N;
}

fn print<T>(_: T)
where
    T: ArrayLen
{
    println!("{}", T::SIZE);
}

fn main() {
    let bytes = include_bytes!("any_file.something");
    print(bytes);
}

然而,[T;CONST_PARAMETER/4]目前是不可能的,但事情可能会随着https://github.com/rust-lang/rust/issues/60471.而改变

鲍鸿波
2023-03-14

通常,不复制就无法将u8的数组转换为u32的数组。

此转换仅在以下条件下有效:

>

  • 对齐。数组需要对齐以容纳u32,这通常意味着它需要从四的倍数开始。对于使用创建的字节数组,请包含_字节!()macro,无法保证合适的对齐方式。这可以用以下代码来说明(playgorund:

    let bytes: [u8; 5] = [1, 2, 3, 4, 5];
    dbg!(bytes.as_ptr().align_offset(std::mem::align_of::<u32>()));
    

    当我尝试在操场上运行它时,结果是1,这意味着字节数组没有对齐以保存u32,但不能保证结果。

    Endianness。数组中的字节必须表示与目标体系结构endianness匹配的endianness中的32位整数。如果从文件加载的数据是little endian格式的,则任何将数据解释为32位整数而不进行任何转换的代码都只能在little endian平台上工作。

    长度。字节数组的长度需要是u32大小的倍数,即4的倍数。

    如果满足这些条件,理论上可以使用以下代码将字节数组转换为u32的切片:

    let audio = unsafe {
        let ptr = bytes.as_ptr() as *const u32;
        let factor = std::mem::size_of::<u32>() / std::mem::size_of::<u8>();
        let len = bytes.len() / factor;
        if ptr.align_offset(std::mem::align_of::<u32>()) == 0
            && bytes.len() % factor == 0
            && cfg!(target_endian = "little")
        {
            std::slice::from_raw_parts(ptr, len)
        } else {
            // Perform proper conversion.
        }
    };
    

    然而,这似乎不值得费心——无论如何,您都需要实现真正的转换代码。

    我的建议是使用实际的音频文件格式,并使用库加载它-这将为您节省各种麻烦。

  •  类似资料:
    • 问题内容: 我声明了一个数组,如下所示: 然后,我为数组分配了以下值: 然后,我声明并初始化了一个整数变量: 这对于查找实际大小将很有用,但是有什么方法可以找到数组的逻辑大小吗? 问题答案: 它包含分配的大小。未分配的指标将包含默认值,即对。

    • 问题内容: 例如,我们可以像这样构造一个数组: 我看到了这样的构造,但是我不明白为什么这可能有用。 问题答案: 一个例子。说,你有一个功能 获取一些文件名。想象一下,您找不到满足条件的文件名。你还回来什么?您有2个选择- 返回null 或 0大小的array 。 大小 为 0的数组 的变体更好,因为您的调用方不需要检查 NULL, 并且可以以一致的方式处理该数组-例如,在循环中(在这种情况下为空)

    • 本文向大家介绍javascript 数组的定义和数组的长度,包括了javascript 数组的定义和数组的长度的使用技巧和注意事项,需要的朋友参考一下 本文提供一款简单的js入门教程,这是一款js数组定义与数组长度实例教程,如果你正在学习js数组的话,我们这里告诉你如何定义数组以及增加数组与数组长度计算实例。 先来看看如何定义数组 或者数组直接量: 下面看一下,在数组后面增加一个元素 数组的长度

    • 让我们假设我有以下切片(代码不编译): 问题是编译器无法推断

    • 问题内容: 我在Java中有一个二维双精度数组,它基本上是一个值表,我想找出它有多少行… 像这样在其他地方声明(并分配): 然后传递给一个函数… 在我的函数中,我想知道每个维度的长度,而不必将其作为参数传递。我可以针对列数执行此操作,但不知道如何针对行执行此操作… 我怎么做? 我可以说… 为什么不给出x列的行? 问题答案: 在Java中,二维数组无非就是数组数组。 这意味着您可以轻松获得以下行数:

    • 我尝试过创建循环,比如减去用户想要购买的物品的数量,同时计算取值时的模数为0,减去用户购买的数量,但我离它还很远。 数组来自其他方法: 是商品的价格是用户购买的商品数量是用户对折扣的选择,例如,用户可以将折扣设置为2包、3包甚至无。