C++ 将二进制文件读入 uint8 数组以返回十进制 int 给出错误结果

问题描述 投票:0回答:1

我尝试解析二进制文件并从中提取不同的数据结构。 其中一个可以是 uint8 或 int8(也可以是 uint16、int16 ... 直到 64)。

为了拥有最通用的方法,我从给定的文件指针读取数据并将其保存在 uint8 数组(缓冲区)中。

通过我的测试,我假设文件内容 40(十六进制)应该导致结果整数 64。 这就是为什么我的测试方法断言这个值是支持的。 ** 不幸的是,uint8 数组的内容结果始终为十进制整数 52。** 我不知道为什么,并尝试了各种其他方法来读取特定数量的字节并将它们分配给整数变量。 这是字节顺序的主题还是什么?

提前致谢,如果有人可以提供帮助:)

我的read_int方法:

int read_int(FILE * file,int n,bool is_signed) throw(){
  assert(n>0);
  uint8_t n_chars[n];
  int result;
  for (int i = 0; i < n; i++)
  {
    if(fread(&n_chars[i],sizeof(n_chars[i]),1,file)!=1){
        std::cerr<< "fread() failed!\n";
        throw new ReadOpFailed();
    }
    result*=255;
    result+=n_chars[i];
  }
    std::cout<< "int read: "<<result<<"\n";
    return result;

//-------------Some ideas that didn't work out either------------------
    // std::stringstream ss;
    // ss << std::hex << static_cast<int>(static_cast<unsigned char>(n_chars)); // Convert byte to hexadecimal string
    // int result;
    // ss >> result; // Parse the hexadecimal string to integer
    // std::cout << "result" << result<<"\n";

一个非常失败的小测试...... 具有字节序检测的部分给出了小字节序的输出(不知道这是否是问题的一部分)。

struct TestContext{
    FILE * create_test_file_hex(char * input_hex,const char * rel_file_path = "test.gguf") {
        std::ofstream MyFile(rel_file_path, std::ios::binary);

        // Write to the file
        MyFile << input_hex;

        // Close the file
        MyFile.close();

        
        // std::fstream outfile (rel_file_path,std::ios::trunc);
        // char str[20] = 
        // outfile.write(str, 20);
        // outfile.close();

        FILE *file = fopen(rel_file_path,"rb");
        try{
            assert(file != nullptr);
        }catch (int e){
            std::cout << "file couldn't be opened due to exception n° "<<std::to_string(e)<<"\n";
            ADD_FAILURE(); 
        }
        std::remove(rel_file_path); //remove file whilst open, to be able to use it, but delete it after the last pointer was deleted.
    return file;
    }
};

TEST(test_tool_functions, test_read_int){
    int n = 1;
    // little endian if true
    if(*(char *)&n == 1) {std::cout<<"Little Endian Detected!!!\n";}
    else{std::cout<<"Big Endian Detected!!!\n";}
    std::string file_hex_content = "400A0E00080000016";
    
    uint64_t should;
    std::istringstream("40") >> std::hex >> should;
    ASSERT_EQ(should,64);
    
    uint64_t result = read_int(TestContext().create_test_file_hex(file_hex_content.data()),1,false);
    ASSERT_EQ(result,should);
}
c++ file parsing binary fread
1个回答
0
投票

问题的根本原因是您的

hex_file_content
由 ASCII 字符组成,而不是所需的二进制字节。因此,它不是以单个字节
0x40
又名
64
开头,而是以一个字节
'4'
(ASCII 字节值
52
)开头,后跟另一个字节
'0'
(ASCII 值
48
)。

下面是一个小型序列化示例。只要您在同一架构上进行序列化和反序列化并且不存在可移植性问题,那么字节序也不是问题。

#include <cstdint>
#include <ios>
#include <iostream>
#include <sstream>

int main() {
  std::stringstream encoded;

  const uint64_t source{0xabcd1234deadbeefULL};
  encoded.write(reinterpret_cast<const char*>(&source), sizeof(source));

  uint64_t target;
  encoded.read(reinterpret_cast<char*>(&target), sizeof(target));

  std::cout << "source == target: " << std::hex << source << " == " << target
            << "\nserialized bytes:";
  for (const uint8_t byte : encoded.str())
    std::cout << ' ' << static_cast<uint32_t>(byte);
  std::cout << std::endl;
}

在我的little endian机器上执行时,以下程序的输出如下所示:

source == target: abcd1234deadbeef == abcd1234deadbeef
serialized bytes: ef be ad de 34 12 cd ab

正如预期的那样,序列化字符串从最低位字节

0xef
开始,以最高位字节
0xab
结束。在big endian机器上,最后一行看起来像整数本身(在这种特殊情况下),即
ab cd 12 34 de ad be ef

© www.soinside.com 2019 - 2024. All rights reserved.