【问题标题】:converting a string read from binary file to integer将从二进制文件读取的字符串转换为整数
【发布时间】:2019-01-07 16:11:40
【问题描述】:

我有一个二进制文件。我使用 fstream 一次读取 16 个字节。

我想将其转换为整数。我试过了。但它没有用。 在 python 中,我们可以通过使用 stringobtained.encode('utf-8') 将其转换为字节流,然后使用 int(bytestring.hex(),16) 将其转换为 int 来实现。我们应该像在 python 中那样遵循这样的 elloborate 步骤,还是有办法直接转换它?

ifstream file(binfile, ios::in | ios::binary | ios::ate);
if (file.is_open())
{

    size = file.tellg();
    memblock = new char[size];
    file.seekg(0, ios::beg);
    while (!file.eof())
    {
        file.read(memblock, 16);            
        int a = atoi(memblock); // doesnt work 0 always
        cout << a << "\n";
        memset(memblock, 0, sizeof(memblock));
    }
    file.close();

编辑:

这是文件的示例内容。

53 51 4C 69 74 65 20 66 6F 72 6D 61 74 20 33 00
04 00 01 01 00 40 20 20 00 00 05 A3 00 00 00 47
00 00 00 2E 00 00 00 3B 00 00 00 04 00 00 00 01

我需要将其读取为 16 个字节,即一次 32 个十六进制数字。(即示例文件内容中的一行)并将其转换为整数。 所以当阅读53 51 4C 69 74 65 20 66 6F 72 6D 61 74 20 33 00时,我应该得到,110748049513798795666017677735771517696

但我做不到。即使在尝试 strtoull 之后,我也总是得到 0。我是不是读错了文件,或者我错过了什么。

【问题讨论】:

  • atoi()以空结尾的文本字符串 转换为整数。除非您的 16 个字节都将最后一个字节设置为 '\0',并且前 15 个字节由前导空格、可选的减号和至少一个介于 '0' 和 '9' 之间的字符组成,否则 atoi() 将不起作用,因为这就是它的作用,也是它唯一的作用(从技术上讲,'\0' 不一定是最后一个字节,但这不是相关的细节)。
  • int 通常为 4 字节,无法存储 16 字节的值。
  • 喜欢这个? stackoverflow.com/q/1070497
  • size = file.tellg(); 我相信这应该返回 0,因为文件刚刚打开。此外,sizeof(memblock) 将返回指针的大小,而不是缓冲区的长度。
  • @JohnnyMopp 在我查找 ios::ate 所做的事情之前,我一直在做同样的事情。那部分代码没问题。

标签: c++ binaryfiles atoi


【解决方案1】:

这里有很多问题。首先是 C++ 没有标准的 128 位整数类型。您也许可以找到编译器扩展,例如参见 Is there a 128 bit integer in gcc?Is there a 128 bit integer in C++?

其次,您正在尝试解码原始字节而不是字符串。 atoi 将在它遇到的第一个非数字字符处停止,256 次中有 246 次将是第一个字节,因此它返回零。如果你很不走运,你将读取 16 个有效数字,atoi 将开始读取未初始化的内存,从而导致未定义的行为。

反正你不需要atoi,你的问题比这简单得多。您只需要将 16 个字节组装成一个整数,这可以通过移位和or 运算符来完成。唯一的复杂之处是 read 想要一个 char 类型,它可能是有符号的,而你需要无符号字节。

ifstream file(binfile, ios::in | ios::binary);
char memblock[16];
while (file.read(memblock, 16))
{
    uint128_t a = 0;
    for (int i = 0; i < 16; ++i)
    {
        a = (a << 8) | (static_cast<unsigned int>(memblock[i]) & 0xff);
    }
    cout << a << "\n";
}
file.close();

【讨论】:

  • 感谢您的想法。但是 uint128_t 和 unsigned __int128 都不适合我。因为我正在使用 MS VSC++ 编译器。但是我用你的方式一次读取 4 个字节并存储在一个字符串中,使用 bitset 将这些字符串连接起来形成 16 字节十六进制值的 128 位二进制等效值。到目前为止,我正在使用该值并右移,因此我不需要存储生成的 128 位二进制字符串。但是关于如何在 vsc++ 中使用 unsigned __128 有什么想法吗?这样可以节省很多时间
  • @Prakrithi 根据this 目前无法使用 VSC++。我刚刚搜索了VS2017中的库,可以确认。
【解决方案2】:

如果数字是二进制你想要的是:

    short value ;
    file.read(&value, sizeof (value));            

根据文件的写入方式和您的处理器,您可能必须使用位操作反转字节值。

【讨论】:

    猜你喜欢
    • 2012-06-24
    • 2012-02-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多