代码之家  ›  专栏  ›  技术社区  ›  Lefteris

将二进制数据读取到long int

  •  1
  • Lefteris  · 技术社区  · 6 年前

    我需要读取包含一列数字(时间标签)的二进制数据,并使用8字节记录每个数字。我知道他们被记录在 小恩迪亚 顺序如果读取正确,应将其解码为(示例)

      ...  
      2147426467  
      2147426635  
      2147512936  
      ...
    

    我认识到上述数字处于2^31-1的阈值上。 我尝试读取数据并用以下方法反转端点: ( 是字节总数,并且 缓冲器 是指向包含字节的数组的指针)

    unsigned long int tag;
    //uint64_t tag;    
    for (int j=0; j<length; j=j+8) //read the whole file in 8-byte blocks
       { tag = 0;  
         for (int i=0; i<=7; i++) //read each block ,byte by byte
            {tag ^=  ((unsigned char)buffer[j+i])<<8*i ;} //shift each byte to invert endiandness and add them with ^=
       }
                                                                                                  }
    

    运行时,代码给出:

      ...  
      2147426467  
      2147426635  
      18446744071562097256  
      similar big numbers   
      ...
    

    最后一个数字不是(2^64-1-正确值)。 使用相同的结果 uint64\U t标签 。 代码成功地将标记声明为

    unsigned int tag;
    

    但对于大于2^32-1的标记失败。至少这是有道理的。
    我想我需要在缓冲区(I+j)上进行一些转换,但我不知道怎么做。

    (static_cast<uint64_t>(buffer[j+i])) 
    

    也不起作用。
    我读过 a similar question 但仍然需要一些帮助。

    2 回复  |  直到 6 年前
        1
  •  0
  •   jxh    6 年前

    我们假设 buffer[j+i] 是一个 char ,以及 烧焦 在您的平台上签名。铸造至 unsigned char 转换 缓冲器[j+i] 转换为无符号类型。但是,当应用 << 操作员 无符号字符 值被提升为 int 只要 内景 可以保存所有可表示的值 无符号字符

    您尝试施放 缓冲器[j+i] 直接发送至 uint64_t 失败,因为如果 烧焦 是有符号的,则在将值转换为无符号类型之前,仍将应用符号扩展名。

    双重强制转换可能有效(即,强制转换为 无符号字符 然后到 unsigned long ),但使用 无符号长 保存中间值的变量应使代码的意图更加明确。对我来说,代码如下所示:

    decltype(tag) val = static_cast<unsigned char>(buffer[j+i]);
    tag ^= val << 8*i;
    
        2
  •  0
  •   Koto    6 年前

    使用临时值。 计算机将自动保留存储临时值所需的最小数量。在您的情况下,这将是32位。 一旦你将字节移位超过32位,它就会被遗忘。 为了解决这个问题,需要先将值显式存储在64位整数中。 因此

        {tag ^=  ((unsigned char)buffer[j+i])<<8*i ;}
    

    你应该用这样的东西

        {
           unsigned long long tmp = (unsigned char)buffer[j+i];
           tmp <<= 8*i;
           tag ^=  tmp;
        }