将二进制数据读取到long int

时间:2018-03-28 18:19:32

标签: c++ casting binaryfiles endianness

我需要读取包含一列数字(时间标记)的二进制数据,并使用8字节来记录每个数字。我知道它们是以 little endian 顺序录制的。如果读取正确,则应将其解码为(示例)

  ...  
  2147426467  
  2147426635  
  2147512936  
  ...

我认识到上述数字是在2 ^ 31 -1的门槛上。 我尝试读取数据并反转endiandness: (长度是总字节数,缓冲区是指向包含字节的数组的指针)

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_t标记的结果相同。 代码成功将标记声明为

unsigned int tag;

但对于大于2 ^ 32 -1的标签失败。至少这是有道理的 我想我需要在缓冲区[i + j]上进行某种渲染,但我不知道该怎么做。

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

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

2 个答案:

答案 0 :(得分:0)

您使用临时值。 计算机将自动保留存储临时值所需的最少量。在你的情况下,这将是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;
    }

答案 1 :(得分:0)

我们假设buffer[j+i]char,并且char已在您的平台上签名。转换为unsigned char会将buffer[j+i]转换为无符号类型。但是,在应用<<运算符时,只要unsigned char可以保存int所代表的所有值,int值就会提升为unsigned char

您将buffer[j+i]直接投放到uint64_t的尝试失败,因为如果char已签名,则在将值转换为无符号类型之前仍会应用符号扩展名。

双重转换可能有效(即转换为unsigned char然后转换为unsigned long),但使用unsigned long变量来保存中间值应该是代码的意图更清晰。对我来说,代码看起来像:

decltype(tag) val = static_cast<unsigned char>(buffer[j+i]);
tag ^= val << 8*i;