Thursday, 22 August 2013

How portable is relying on sizeof for structures without padding

How portable is relying on sizeof for structures without padding

In code I have to maintain, some array serialization (e.g. std::vector<T>)
happens roughly the following way: there is an array_t structure without
padding:
#pragma pack(push, 1)
template <typename T, uint32_t N>
struct array_t
{
typedef T value_type;
static uint32_t const max_length = N;
uint32_t length;
value_type data[max_length];
value_type const & operator[](uint32_t k) { return data[k]; }
value_type & operator[](uint32_t k) { return data[k]; }
template <typename Container>
void from_container(Container const & c)
{
std::copy(c.begin(), c.end(), &(*this)[0]);
length = c.size();
}
template <typename Container>
Container to_container() const
{
return Container(&(*this)[0], &(*this)[length]);
}
};
#pragma pack(pop)
And when such datatypes need to be sent over the network, what happens is
(very simplified):
template <typename T>
char * serialize(T const & data)
{
void * buf = std::malloc(sizeof(T));
std::memcpy(buf, &data, sizeof(T));
return reinterpret_cast<char *>(buf);
}
std::string const s("This is some string");
typedef array_t<char, 64> arr_str;
arr_str serial;
serial.from_container(s);
char * buf = serialize(serial);
network.send(buf); // frees the memory as well
And on the other end this method is called:
template <typename T>
T deserialize(char * ptr)
{
T data;
std::memcpy(&data, ptr, sizeof(T));
std::free(ptr);
return data;
}
arr_str deserial = deserialize<arr_str>(buf);
We do not need to argue that this is not the best way of serializing
objects. What concerns me now: how portable is that? The comments of these
methods say that this is guaranteed to work on every x86/x64 system - is
that claim true?

No comments:

Post a Comment