Reputation: 57
Im going to send a int64 over tcp and need to serialize&deserialize it.
First i cast it to a uin64.
I byteshift it into an uint8 array.
Then i byteshift the array into a uint64
And finally cast it back to a int.
But it returns a different value than i put in... I have checked the hex values, but they are supposed to be correct...
Code:
#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;
}
Output:
INPUT: 1234567890
RESULT: 316049379840
Been trying to solve this for a day now, cant find the problem
Thanks.
Upvotes: 1
Views: 1528
Reputation: 21
you are missing a bit shift in the bytesToInt64
function:
below you find the corrected bytesToInt64
function:
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;
}
Upvotes: 2
Reputation: 636
This should work. You may also need to check the input array is the right size in your bytesToInt64 function.
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;
}
Upvotes: 0
Reputation: 4297
If you're transferring data between machines with the same endianness you don't need to serialize the data byte by byte, you can just send the data as it is represented in memory. In this case you don't need anything like that you can just use your memcpy call like this:
// Serialize
memcpy(&bytes, &val, sizeof(val));
// Deserialize
int64_t val2;
memcpy(&val2, &bytes, sizeof(val));
If you're sending data between hosts with different endianness you should send it as you find it in the aswer from Roger, basically you have to make sure the data is represented in the same way on both ends.
here's a variant which not only serializes but will work with any type of int and across any platforms
#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;
}
you should probably use containers and parts to serialize/deserialize data to make sure you don't overflow your buffer (considering you are transferring more than one int at a time)
Upvotes: 1
Reputation:
Try using the uint64_t htobe64(uint64_t host_64bits) and uint64_t be64toh(uint64_t big_endian_64bits) functions to convert from host to big endian (network order) and from network order to host order respectively.
You are shifting the entire value. Try something like:
(bytes[0] << 56) |
(bytes[1] << 48) |
... (bytes[7])
There is no 9th byte (ie. byte[8]).
Upvotes: 3