0

i wonder if nobody is using an union to serialize structs for boost::asio sender/receiver. i have searched for something but all i found (yet) were been examples like this or this.

so i have it done like this:

struct ST {
  short a;
  long b;
  float c;
  char c[256];
}
... 

void sender::send(const ST &_packet) {
  union {
    const ST &s;
    char (&c)[sizeof(ST)];
  }usc = {_packet};

  socket.send_to(boost::asio::buffer(usc.c, sizeof(ST)), endpoint);
}
...

ST var = {1234, -1234, 1.4567, "some text"};
sercer.send(var);

so my question now is, is this bad practise to do serialization of the fundamental data types?

i know i can't send var-sized strings directly, and therefor i can use boost::serialization.

Community
  • 1
  • 1
user1810087
  • 5,146
  • 1
  • 41
  • 76
  • IMHO, yes, this is pretty horrible. Why don't you just `static_cast` to a `void*`, and pass that. It'd be much more readable, and more representative of what you seem to be trying to do. – radical7 Feb 14 '13 at 14:48
  • I would consider it a bad practice as you are violating strict aliasing rules and thus invoking undefined behavior. Using static_cast as suggested by radical7 doesn't help either though. – Karel Petranek Feb 14 '13 at 14:50

1 Answers1

1

It is indeed bad practise. What you are sending is (supposed to be) a sequence of bytes containing the exact binary representation of whatever is in the union on your system. The problems are:

  1. You fill the usc union with a ST, but access it as a char[], which produces undefined behavior (but probably works on all common systems).
  2. You probably want to do the same on the receiver side, in reversed order. UB again, but probably works.
  3. Here comes trouble: You send the data in a system specific format, that need not be the same on the receiving system, for the same struct definition. This includes
    • byte order of integral types (little/big endian)
    • size of types, not only integral (e.g. sizeof(long) sometimes differs from 32bit to 64bit systems, or between different compilers on 64bit systems)
    • padding bytes
    • sizeof(ST) itself may differ significantly

Simply said: just don't do this. If you are using boost::serialization anyways, use it for the whole ST struct, not only for the strings inside it. If your data structure becomes just a little more complicated (e.g. contains pointers, has nontrivial constructors etc.) you have to do that anyways.

Arne Mertz
  • 24,171
  • 3
  • 51
  • 90
  • so do boost::serialization guarantee me to avoid the troubles you described? – user1810087 Feb 14 '13 at 16:30
  • Boost.Serialization is indeed purposely designed to avoid those troubles. See bullet 7 in the [list here](http://www.boost.org/doc/libs/1_53_0/libs/serialization/doc/overview.html#Requirements). That is, of course, if you don't use a custom serialization that depends on such platform specific things. – Arne Mertz Feb 15 '13 at 08:03