1

How can I convert a long long to an array of char's that match up in the binary values? I'm working on a program where a binary string is sent over a network to control a lighting system. The way I have it set up now is I have a function that receives an std::string, then sends that to the clients. I would really like to keep this architecture (std::strings are easy to pass back and forth)?

Edit: I'm looking for a binary serialization of a long long type as an array of bytes.

HSchmale
  • 1,838
  • 2
  • 21
  • 48
  • Perhaps via `std::bitset`? Or are you looking for a binary serialization of a `long long`? – Columbo Jan 20 '15 at 22:46
  • @Columbo I'm looking for the binary serialization. – HSchmale Jan 20 '15 at 22:48
  • 1
    reinterpret_cast then? – Columbo Jan 20 '15 at 23:03
  • Do you want 8 or 64 chars? If 8, be careful about processing the NUL-char. As in this case it does not signify the end of the string. E.g. concatenating such values and applying `strlen()` won't work. – Sebastian Jan 16 '22 at 16:46
  • Be also careful with undefined behavior and strict aliasing: unions for type pruning only legally work in C. Using `reinterpret_cast` for this also violates the rules and can sometimes lead to hard-to-find bugs. `bit_cast` (since C++20) is the correct cast and `memcpy` of the 8 bytes (often optimized by the compiler to register operations!) are the official ways. – Sebastian Jan 16 '22 at 17:03
  • Okay, `reinterpret_cast` to `char`, `unsigned char` and `byte` is allowed; but not back again in the other direction (https://en.cppreference.com/w/cpp/language/reinterpret_cast#Type_aliasing) – Sebastian Jan 16 '22 at 18:11

2 Answers2

2

If you don't mind using raw char array, you could simply go for:

char c[sizeof (long long)];
memcpy(c, &longlongValue, sizeof (long long));

edit:

or even:

char c[sizeof (long long)];
*(long long*)c = longlongValue;

which will probably be faster than a call to memcpy.

I agree this is not pretty c++, or c for that matter.

ThreeStarProgrammer57
  • 2,906
  • 2
  • 16
  • 24
  • 1
    `long long` is a type, so it must be put inside brackets like this `sizeof(long long)`. Only with a variable you can omit the parentheses – phuclv Jan 21 '15 at 08:42
1

One thing you might consider is that the client and server on the network may have different endianness.

The Internet Protocol defines big-endian as the standard network byte order used for all numeric values in the packet headers and by many higher level protocols and file formats that are designed for use over IP. The Berkeley sockets API defines a set of functions to convert 16-bit and 32-bit integers to and from network byte order: the htons (host-to-network-short) and htonl (host-to-network-long) functions convert 16-bit and 32-bit values respectively from machine (host) to network order; the ntohs and ntohl functions convert from network to host order. These functions may be a no-op on a big-endian system.

network byte order, that is, big-endian. There is no standard library call to convert long long to and from network-byte-order. Following are some templates that can be used to serialize and deserialize any integral type to and from a std::string in network-byte-order. Live demo here.

To serialize

template< typename T >
string serialize( T val ) {
    string str( sizeof(T), 0 );
    for(size_t i=0; i<sizeof(T); ++i, val >>= 8)
        str[sizeof(T)-i-1] = char(val);
    return str;
}

To deserialize

template< typename T >
T deserialize( const string & data ) {
    T val = 0;
    for(unsigned char u : data) val = (val << 8) | u;
    return val;
}

And use it like this

long long val = 201501210654;
std::string str = serialize(val);
assert( val == deserialize<long long>( str ) );
amdn
  • 11,314
  • 33
  • 45