Десериализация массива uint8 в int64 не удалась, но должна работать - PullRequest
1 голос
/ 15 марта 2019

Я собираюсь отправить int64 через tcp, и мне нужно его сериализовать и десериализовать.

Сначала я бросил его на 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

Пытался решить эту проблему в течение дня, не могу найти проблему

Спасибо.

Ответы [ 4 ]

2 голосов
/ 15 марта 2019

Попробуйте использовать функции uint64_t htobe64 (uint64_t host_64bits) и uint64_t be64toh (uint64_t big_endian_64bits) для преобразования из хоста в порядковый номер (порядок сети) и из сетевого порядка в порядок хоста соответственно.

Вы сдвигаете все значение. Попробуйте что-то вроде:

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

Нет 9-го байта (т. Е. Байта [8]).

0 голосов
/ 15 марта 2019

Это должно работать. Вам также может понадобиться проверить правильность размера входного массива в вашей функции 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;
}
0 голосов
/ 15 марта 2019
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];
   return (int64_t)v;
}
0 голосов
/ 15 марта 2019

Если вы передаете данные между машинами с одинаковым порядком байтов, вам не нужно сериализовать данные побайтно, вы можете просто отправить данные, как они представлены в памяти. В этом случае вам не нужно ничего подобного, вы можете просто использовать свой вызов memcpy следующим образом:

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

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

Если вы отправляете данные между хостами с различным порядком байтов, вы должны отправлять их так, как вы нашли их в ответе от Роджера, в основном вы должны убедиться, что данные представлены одинаково на обоих концах.

вот вариант, который не только сериализует, но и будет работать с любым типом 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;
}

вам, вероятно, следует использовать контейнеры и части для сериализации / десериализации данных, чтобы убедиться, что вы не переполняете свой буфер (учитывая, что вы передаете более одного целого числа за раз)

...