Does htonl and nthol only work with integers? Can I use those conversions for float data
To manage float you can for instance use an union to transform float in a uint32_t
and vice versa, or use a cast of a pointer of float to a pointer of uint32_t
and vice versa, of course do not cast a float to uint32_t
and reverse
But you seem to work an double rather than float, in that case you need to use htobe64/htole64/be64toh/le64toh (endian.h
), if they are not defined under Windows decide the order or the bytes in your packet and define the conversion by yourself
What is the byte order of a frame in linux and windows
The order is only dependent on the CPU, not on the OS
I know that the sendto () function returns the number of bytes that are being sent. What I send are 20Bytes -> (2 * 8Bytes (double) + 1 * 4Bytes (ulong)) = 20Bytes. But the function returns 24Bytes, how can this be? Is it due to UDP protocol headers or is it additional information that includes Windows?
You only access to the payload, all the header/footer/etc are hidden to you
Probably you send a struct rather than making yourself the packet to send, in that case the compilers just do not follow the same padding or the size of a long is 32b on one and 64b on the other ?
Do not send a struct, copy the numbers in a vector of bytes managing the endian, and extract them in the same way
For instance doing all by hand, an unsigned long is read/write on 8 bytes to allow to be compatible even if they have 64b on a host and less on the other :
#include <string.h>
void encDec32(char * a, char * b)
{
const int e = 1;
if (*((char *) &e)) {
memcpy(a, b, 4);
}
else {
a[0] = b[3];
a[1] = b[2];
a[2] = b[1];
a[3] = b[0];
}
}
void encDec64(char * a, char * b)
{
const int e = 1;
if (*((char *) &e)) {
memcpy(a, b, 8);
}
else {
a[0] = b[7];
a[1] = b[6];
a[2] = b[5];
a[3] = b[4];
a[4] = b[3];
a[5] = b[2];
a[6] = b[1];
a[7] = b[0];
}
}
void encodeU32(char ** buffer, uint32_t v)
{
encDec32(*buffer, (char *) &v);
*buffer += 4;
}
void encodeU64(char ** buffer, uint64_t v)
{
encDec64(*buffer, (char *) &v);
*buffer += 8;
}
void encodeFloat(char ** buffer, float v)
{
encDec32(*buffer, (char *) &v);
*buffer += 4;
}
void encodeDouble(char ** buffer, double v)
{
encDec64(*buffer, (char *) &v);
*buffer += 8;
}
void encodeUlong(char ** buffer, unsigned long v)
{
/* force on 8 bytes to be compatible with CPU 32 and 64 */
encodeU64(buffer, (uint64_t) v);
}
uint32_t decodeU32(char ** buffer)
{
uint32_t v;
encDec32((char *) &v, *buffer);
*buffer += 4;
return v;
}
uint64_t decodeU64(char ** buffer)
{
uint64_t v;
encDec64((char *) &v, *buffer);
*buffer += 8;
return v;
}
float decodeFloat(char ** buffer)
{
float v;
encDec32((char *) &v, *buffer);
*buffer += 4;
return v;
}
float decodeDouble(char ** buffer)
{
double v;
encDec64((char *) &v, *buffer);
*buffer += 8;
return v;
}
unsigned long decodeUlong(char ** buffer)
{
/* force on 8 bytes to be compatible with CPU 32 and 64 */
return (unsigned long) decodeU64(buffer);
}
/* for a struct */
typedef struct S {
unsigned long u; /* may be on 32 or 64 and not the same size on Linuw and Windows */
double d1;
double d2;
} S;
/* b is the block to send, it must be enough long */
/* return the number of bytes to send in a block through UDP */
size_t encodeS(char * b, S * s)
{
char * b0 = b;
encodeUlong(&b, s->u);
encodeDouble(&b, s->d1);
encodeDouble(&b, s->d2);
return b - b0;
}
/* b is the block read through UDP */
void decodeS(char * b, S * s)
{
s->u = decodeUlong(&b);
s->d1 = decodeDouble(&b);
s->d2 = decodeDouble(&b);
}