将存储在u32数组中的大数转换为字节并返回

时间:2018-01-08 22:11:17

标签: rust

我在Rust中做了一些计算数学,而且我有一些大数字,我存储在24个值的数组中。我有将它们转换为字节并返回的函数,但它对u32值不起作用,而它适用于u64。代码示例可以在下面找到:

fn main() {
    let mut bytes = [0u8; 96]; // since u32 is 4 bytes in my system, 4*24 = 96
    let mut j;
    let mut k: u32;

    let mut num: [u32; 24] = [1335565270, 4203813549, 2020505583, 2839365494, 2315860270, 442833049, 1854500981, 2254414916, 4192631541, 2072826612, 1479410393, 718887683, 1421359821, 733943433, 4073545728, 4141847560, 1761299410, 3068851576, 1582484065, 1882676300, 1565750229, 4185060747, 1883946895, 4146];
    println!("original_num: {:?}", num);

    for i in 0..96 {
        j = i / 4;
        k = (i % 4) as u32;
        bytes[i as usize] = (num[j as usize] >> (4 * k)) as u8;
    }

    println!("num_to_ytes: {:?}", &bytes[..]);
    num = [0u32; 24];

    for i in 0..96 {
        j = i / 4;
        k = (i % 4) as u32;
        num[j as usize] |= (bytes[i as usize] as u32) << (4 * k);
    }

    println!("recovered_num: {:?}", num);
}

Rust playground

上面的代码没有从字节数组中检索正确的数字。但是,如果我将所有u32更改为u64,将所有4更改为8 s,并将num的大小从24个值减少到12,工作得很好。我假设u32版本存在一些逻辑问题。正确运行的u64版本可在this Rust playground中找到。

1 个答案:

答案 0 :(得分:7)

学习如何创建MCVE是编程时的一项重要技能。例如,为什么你有一个阵列?为什么重用变量?

您的原始第一个号码是0x4F9B1BD6,输出的第一个号码是0x000B1BD6

比较中间字节表明你有垃圾:

let num = 0x4F9B1BD6_u32;
println!("{:08X}", num);

let mut bytes = [0u8; BYTES_PER_U32];
for i in 0..bytes.len() {
    let k = (i % BYTES_PER_U32) as u32;
    bytes[i] = (num >> (4 * k)) as u8;
}

for b in &bytes {
    print!("{:X}", b);
}
println!();
4F9B1BD6
D6BD1BB1

打印出k

的值
for i in 0..bytes.len() {
    let k = (i % BYTES_PER_U32) as u32;
    println!("{} / {}", k, 4 * k);
    bytes[i] = (num >> (4 * k)) as u8;
}

显示您尝试按 4 位的倍数移位:

0 / 0
1 / 4
2 / 8
3 / 12

我非常确定今天的每个通用平台都使用 8 位作为字节,而不是 4

这是为什么魔术数字不好。如果你已经使用常量作为值,你会更快地注意到这个问题。

  

因为u32在我的系统中是4个字节

每个系统上的u32 更好为4个字节 - 这就是 u32的原因

总的来说,不要重新发明轮子。使用byteorder crate或等价物:

extern crate byteorder;

use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};

const LENGTH: usize = 24;
const BYTES_PER_U32: usize = 4;

fn main() {
    let num: [u32; LENGTH] = [
        1335565270, 4203813549, 2020505583, 2839365494, 2315860270, 442833049, 1854500981,
        2254414916, 4192631541, 2072826612, 1479410393, 718887683, 1421359821, 733943433,
        4073545728, 4141847560, 1761299410, 3068851576, 1582484065, 1882676300, 1565750229,
        4185060747, 1883946895, 4146,
    ];
    println!("original_num: {:?}", num);

    let mut bytes = [0u8; LENGTH * BYTES_PER_U32];
    {
        let mut bytes = &mut bytes[..];
        for &n in &num {
            bytes.write_u32::<BigEndian>(n).unwrap();
        }
    }

    let mut num = [0u32; LENGTH];
    {
        let mut bytes = &bytes[..];
        for n in &mut num {
            *n = bytes.read_u32::<BigEndian>().unwrap();
        }
    }

    println!("recovered_num: {:?}", num);
}