Hm, I've been toying around with Antonio's answer, as it didn't feel complete and correct, and in the end I ended with something more complex than I expected, but complexity has it's purpose sometimes.
Following code is doing among other things also htonl
/ntohl
-like conversion manually (maybe in opposite endianness, so it's not desirable to mix this with htonl
, use either this, or rewrite it with htonl
).
Unlike Antonio's source, it will not overwrite memory when input number type is 8 bytes long (unsigned long
is 8 bytes on my test platform - BTW, try it?!), it will instead truncate the value to fit into the desired network char* buffer.
I tried to comment it extensively to give you idea behind each decision to add further complexity (to what is basically using unsigned int number
used as (char *)(&number)
, which delivers too, but doesn't guard endianness, and may end in overwriting memory if you mix up different length types). But ask anything if you see something unclear.
#include <iostream>
#include <string>
// Experiment with different types to see differences
// (and how data are truncated when sizeof number > sizeof networkdata)
//typedef unsigned int numberType_t;
typedef unsigned long numberType_t; // on my platform this is 8 bytes long
constexpr int networkBytesSize = 4; // number of chars to be sent trough network with (char *)
// define network data type:
// used "struct" to make sizeof(networkData_t) return actual number of bytes
typedef struct {
unsigned char d[networkBytesSize];
char *cptr() { return reinterpret_cast<char *>(d); }
} networkData_t;
// Writes number into network char* buffer nrAsByte, endianness agnostic
void number2char(numberType_t number, networkData_t & nrAsByte) {
for (size_t i = 0; i < sizeof(networkData_t); ++i) {
nrAsByte.d[i] = number & 0xFF;
number >>= 8;
}
}
// Read number back from network char* buffer
numberType_t char2number(const networkData_t & nrAsByte) {
numberType_t number = 0;
size_t i = sizeof(networkData_t);
while (i--) number = (number<<8) | nrAsByte.d[i];
return number;
}
int main()
{
printf("numberType_t size in bytes: %lu, networkData_t size in bytes: %lu\nAll following numbers are hex:\n",
sizeof(numberType_t), sizeof(networkData_t));
numberType_t number = numberType_t(0x9ABCDEF0123456FEul);
std::cout << "source number: " << std::hex << number << std::endl;
// Write number into char buffer
networkData_t networkData;
number2char(number, networkData);
std::cout << "network bytes:";
for (size_t i = 0; i < sizeof(networkData_t); ++i) std::cout << " [" << unsigned(networkData.d[i]) << "]";
std::cout << std::endl;
// Test usability of (char *) pointer access
const char * testCharPtrConversion = networkData.cptr();
printf("as char * (decimal signed): %d %d ...\n", testCharPtrConversion[0], testCharPtrConversion[1]);
// Read number from char buffer
number = char2number(networkData);
std::cout << "read number: 0x" << std::hex << number << std::endl;
}