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

为什么为无符号整数复制C的fread的泛型函数总是返回零?

孔城
2023-03-14

我正在尝试从16位架构中读取二进制16位机器指令(其确切性质在这里无关紧要),并将它们打印回十六进制值。在C中,我发现这很简单,方法是使用fread函数将16位读入uint16_t

我想我会尝试在Rust中复制fread。如果我能提前知道被读入的变量的确切大小,这似乎是相当微不足道的,而且我专门为16位工作。

我决定尝试使fread函数在各种内置无符号整数类型上通用。为此,我使用Num crate中的一些特征提出了以下函数:

fn fread<T>(
    buffer: &mut T,
    element_count: usize,
    stream: &mut BufReader<File>,
) -> Result<usize, std::io::Error>
where
    T: num::PrimInt + num::Unsigned,
{
    let type_size = std::mem::size_of::<T>();
    let mut buf = Vec::with_capacity(element_count * type_size);
    let buf_slice = buf.as_mut_slice();

    let bytes_read = match stream.read_exact(buf_slice) {
        Ok(()) => element_count * type_size,
        Err(ref e) if e.kind() == std::io::ErrorKind::UnexpectedEof => 0,
        Err(e) => panic!("{}", e),
    };

    *buffer = buf_slice
        .iter()
        .enumerate()
        .map(|(i, &b)| {
            let mut holder2: T = num::zero();
            holder2 = holder2 | T::from(b).expect("Casting from u8 to T failed");
            holder2 << ((type_size - i) * 8)
        })
        .fold(num::zero(), |acc, h| acc | h);
    Ok(bytes_read)
}

问题是当我在main函数中调用它时,我似乎总是得到0x00返回,但函数返回的读取字节数总是2,因此程序进入无限循环:

extern crate num;

use std::fs::File;
use std::io::BufReader;
use std::io::prelude::Read;

fn main() -> Result<(), std::io::Error> {
    let cmd_line_args = std::env::args().collect::<Vec<_>>();

    let f = File::open(&cmd_line_args[1])?;
    let mut reader = BufReader::new(f);
    let mut instructions: Vec<u16> = Vec::new();

    let mut next_instruction: u16 = 0;
    fread(&mut next_instruction, 1, &mut reader)?;

    let base_address = next_instruction;

    while fread(&mut next_instruction, 1, &mut reader)? > 0 {
        instructions.push(next_instruction);
    }

    println!("{:#04x}", base_address);

    for i in instructions {
        println!("0x{:04x}", i);
    }

    Ok(())
}

在我看来,我似乎从来没有从文件中读取任何东西,所以该函数总是只返回它应该读取的字节数。我显然没有在这里正确使用某些东西,但老实说,我不确定我做错了什么。

这是在Rust 1.26 stable for Windows上编译的,如果这很重要的话。

我做错了什么,我应该做些什么来复制fread?我意识到这可能是XY问题的一个例子(因为几乎可以肯定有一种更好的Rust方法来重复读取文件中的一些字节并将它们打包到一个无符号整数中),但我真的很好奇我在这里做错了什么。

共有2个答案

酆英达
2023-03-14

因为几乎可以肯定有一种更好的Rust方法可以从文件中重复读取一些字节并将它们打包成一个无符号整数

是的,使用字节顺序板条箱。这不需要不必要的堆分配(原始代码中的Vec):

extern crate byteorder;

use byteorder::{LittleEndian, ReadBytesExt};
use std::{
    fs::File, io::{self, BufReader, Read},
};

fn read_instructions_to_end<R>(mut rdr: R) -> io::Result<Vec<u16>>
where
    R: Read,
{
    let mut instructions = Vec::new();
    loop {
        match rdr.read_u16::<LittleEndian>() {
            Ok(instruction) => instructions.push(instruction),
            Err(e) => {
                return if e.kind() == std::io::ErrorKind::UnexpectedEof {
                    Ok(instructions)
                } else {
                    Err(e)
                }
            }
        }
    }
}

fn main() -> Result<(), std::io::Error> {
    let name = std::env::args().skip(1).next().expect("no file name");

    let f = File::open(name)?;
    let mut f = BufReader::new(f);

    let base_address = f.read_u16::<LittleEndian>()?;
    let instructions = read_instructions_to_end(f)?;

    println!("{:#04x}", base_address);

    for i in &instructions {
        println!("0x{:04x}", i);
    }

    Ok(())
}
皇甫飞宇
2023-03-14

你的问题是这一行:

let mut buf = Vec::with_capacity(element_count * type_size);

创建一个零长度向量,即使它为element\u count*type\u size字节分配内存。因此,你在问流。read_exact读取零字节。解决此问题的一种方法是将上述行替换为:

let mut buf = vec![0; element_count * type_size];

旁注:当读取成功时,bytes\u read接收到的是预期读取的字节数,而不是实际读取的字节数。您可能应该使用std::mem::size_of_val(buf_slice)来获得真正的字节计数。

 类似资料:
  • 问题内容: 我在某处读到,函数应始终仅返回一种类型,因此以下代码被视为错误代码: 我想更好的解决方案是 返回None然后创建一个新的空元组不是更便宜的内存明智的选择吗?或者即使在较大的项目中,这种时差也太小而无法引起注意? 问题答案: 为什么函数应该返回一致类型的值?满足以下两个规则。 规则1-函数具有“类型”-输入映射到输出。它必须返回一致的结果类型,否则它不是函数。一团糟。 从数学上讲,我们说

  • 我正在学习Python,我不确定这个问题是否是特定的语言,以及是如何在Python中实现的。

  • 未定义行为的一个例子是在flow上的整数行为 有没有一个历史的或者(甚至更好!)造成这种差异的技术原因是什么?

  • 我使用的是Laravel,并有一个查询,它使用列的进行选择: 我已经安装了mysqldn,AFAIK Laravel使用。 但是是一个字符串,不管列是什么类型。(它是一个整数列) 另外,如果我这样做: < code>foo_bar以整数形式返回。

  • 我使用的是我的代码中有两个可观察的对象 观察值不是来自请求,而是来自 我需要根据这个逻辑将序列组合/转换成一个单一的可观察值: 如果序列,或,-需要返回新的可观察的否则需要返回 我试图使用来实现: 但问题是我的