【问题标题】:Deserialization of uint8 array to int64 fails but should work将 uint8 数组反序列化为 int64 失败但应该可以工作
【发布时间】:2019-08-06 10:07:09
【问题描述】:

我要通过 tcp 发送一个 int64 并且需要对其进行序列化和反序列化。

首先我将其转换为 uin64。

我将它字节转换成一个 uint8 数组。

然后我将数组字节转换为 uint64

最后将其转换回 int。

但它返回的值与我输入的不同... 我检查了十六进制值,但它们应该是正确的......

代码:

#include <math.h>
#include <string.h>
#include <iostream>
#include <iomanip>

//SER & D-SER int64
std::array<uint8_t, 8> int64ToBytes(int64_t val)
{
   uint64_t v = (uint64_t)val;
   std::array<uint8_t, 8> bytes;
   bytes[0] = (v&0xFF00000000000000)>>56;
   bytes[1] = (v&0x00FF000000000000)>>48;
   bytes[2] = (v&0x0000FF0000000000)>>40;
   bytes[3] = (v&0x000000FF00000000)>>32;
   bytes[4] = (v&0x00000000FF000000)>>24;
   bytes[5] = (v&0x0000000000FF0000)>>16;
   bytes[6] = (v&0x000000000000FF00)>>8;
   bytes[7] = (v&0x00000000000000FF);
   return bytes;
}

int64_t bytesToInt64(uint8_t bytes[8])
{
   uint64_t v = 0;
   v |= bytes[0]; v <<= 8;
   v |= bytes[1]; v <<= 8;
   v |= bytes[3]; v <<= 8;
   v |= bytes[4]; v <<= 8;
   v |= bytes[5]; v <<= 8;
   v |= bytes[6]; v <<= 8;
   v |= bytes[7]; v <<= 8;
   v |= bytes[8];
   return (int64_t)v;
}


int main() {
   uint8_t bytes[8] = {0};

   int64_t val = 1234567890;

   //Print value to be received on the other side
   std::cout << std::dec << "INPUT:  " << val << std::endl;

   //Serialize
   memcpy(&bytes, int64ToBytes(val).data(), 8);

   //Deserialize
   int64_t val2 = bytesToInt64(bytes);

   //print deserialized int64
   std::cout << std::dec << "RESULT: " << val2 << std::endl;
}

输出:

INPUT:  1234567890
RESULT: 316049379840

解决了一天,没找到问题

谢谢。

【问题讨论】:

  • 在您的 bytesToInt64 函数中,您缺少 byte[2] 索引,因此反向函数与转换函数不同。如果您更正了索引,您的功能可能会很好地工作。

标签: c++ serialization deserialization byte-shifting


【解决方案1】:

尝试使用 uint64_t htobe64(uint64_t host_64bits) 和 uint64_t be64toh(uint64_t big_endian_64bits) 函数分别从主机转换为大端(网络顺序)和从网络顺序转换为主机顺序。

您正在转移整个价值。尝试类似:

(bytes[0] << 56) | 
(bytes[1] << 48) |
...  (bytes[7])

没有第 9 个字节(即 byte[8])。

【讨论】:

    【解决方案2】:

    您在 bytesToInt64 函数中缺少一个位移位:

    您可以在下面找到更正后的 bytesToInt64 函数:

    int64_t bytesToInt64(uint8_t bytes[8])
    {
       uint64_t v = 0;
       v |= bytes[0]; v <<= 8;
       v |= bytes[1]; v <<= 8;
       v |= bytes[2]; v <<= 8;
       v |= bytes[3]; v <<= 8;
       v |= bytes[4]; v <<= 8;
       v |= bytes[5]; v <<= 8;
       v |= bytes[6]; v <<= 8;
       v |= bytes[7];
       return (int64_t)v;
    }
    

    【讨论】:

    • 疯了,我看了这么长时间的代码却没有注意到
    【解决方案3】:

    如果您在具有相同字节顺序的机器之间传输数据,则不需要逐字节序列化数据,您可以发送内存中表示的数据。在这种情况下,您不需要任何类似的东西,您可以像这样使用 memcpy 调用:

    // Serialize
    memcpy(&bytes, &val, sizeof(val));
    
    // Deserialize
    int64_t val2;
    memcpy(&val2, &bytes, sizeof(val));
    

    如果您在具有不同字节序的主机之间发送数据,您应该按照您在 Roger 的 aswer 中找到的发送数据,基本上您必须确保数据在两端以相同的方式表示。

    这是一个变体,它不仅可以序列化,而且可以与任何类型的 int 以及跨任何平台一起使用

    #include <iostream>
    #include <type_traits>
    
    using namespace std;
    
    template <typename T> enable_if_t<is_integral_v<T>> serialize(T t, char *buf)
    {
        for(auto i = 0U; i < sizeof(t); ++i) {
            buf[i] = t & 0xff;
            t >>= 8;
        }
    }
    
    template <typename T> enable_if_t<is_integral_v<T>> deserialize(T &t, char const *buf)
    {
        for(auto i = 0U; i < sizeof(t); ++i) {
            t <<= 8;
            t |= buf[sizeof(t) - 1 - i];
        }
    }
    
    int main() {
        int64_t t1 = 0x12345678;
    
        int64_t t2{0};
    
        char buffer[sizeof(t1)];
        serialize(t1, buffer);
    
        deserialize(t2, buffer);
    
        cout << "I got " << hex << t2 << endl;
    }
    

    您可能应该使用容器和部件来序列化/反序列化数据,以确保不会溢出缓冲区(考虑到您一次传输多个 int)

    【讨论】:

    • 我不知道我可能将接收软件放在什么机器上,所以我序列化它只是为了确定^^
    【解决方案4】:

    这应该可行。您可能还需要在 bytesToInt64 函数中检查输入数组的大小是否正确。

    std::array<uint8_t, 8> int64ToBytes(int64_t val)
    {
        uint64_t v = (uint64_t)val;
        std::array<uint8_t, 8> bytes;
        for (size_t i = 0; i < 8; i++)
        {
            bytes[i] = (v >> (8 * (7 - i))) & 0xFF;
        }
        return bytes;
    }
    
    int64_t bytesToInt64(uint8_t bytes[8])
    {
        uint64_t v = 0;
        for (size_t i = 0; i < 8; i++)
        {
            v |= (bytes[i] << (8 * (7 - i)));
        }
        return (int64_t)v;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-03-10
      • 2011-07-28
      • 2023-03-20
      • 2015-09-22
      • 2021-03-03
      • 1970-01-01
      • 2022-11-08
      相关资源
      最近更新 更多