将 uint8 数组反序列化为 int64 失败但应该可以

Deserialization of uint8 array to int64 fails but should work

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

首先我将它转换为 uin64。

我将它字节移位到一个 uint8 数组中。

然后我将数组字节移位为 uint64

最后将其转换回整数。

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

代码:

#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

已经尝试解决一天了,找不到问题

谢谢。

尝试使用 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])。

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

// Serialize
memcpy(&bytes, &val, sizeof(val));

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

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

这里有一个变体,它不仅可以序列化,而且可以与任何类型的 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;
}

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

您在 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;
}

这应该有效。您可能还需要在 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;
}