Reputation: 555
I have written a MariaDB/MySQL UDF in C for working with spatial data. I data is available to the function as an unsigned char*. The binary encoding of the data begins with a toggle bit signalling whether the stream is encoded little endian or big endian. Since this is the case I have used the following macros to read the unsigned 32 bit ints from the stream:
#define U32BIT_LE_DATA(ptr) (*(ptr)<<0) | (*(ptr + 1)<<8) | (*(ptr + 2)<<16) | (*(ptr + 3)<<24)
#define U32BIT_BE_DATA(ptr) (*(ptr + 3)<<0) | (*(ptr + 2)<<8) | (*(ptr + 1)<<16) | (*(ptr)<<24)
uint32_t var = U32BIT_LE_DATA(ptr); // Little endian encoding
uint32_t var = U32BIT_BE_DATA(ptr); // Big endian encoding
The stream also has doubles that I need to parse (64-bit (8 byte) double-precision data using the IEEE 754 double-precision format). I know I can do:
double var;
memcpy(&var, ptr, sizeof(double));
But this code is not very safe in regards to portability. I am aware that if I know my machines endiannes, then I can simply reverse the order of the bytes before calling memcpy
. Nevertheless, is there a more reliable way to decode a double from or encode it to a 64bit IEEE 754 double-precision floating point using a specified endianness without needing to know the endianness (and system specific double layout) of the machine running the code?
Upvotes: 0
Views: 233
Reputation: 67749
typedef union
{
double d;
uint8_t b[sizeof(double)];
}u64;
inline double toDoubleLE(const uint8_t *arr, int endianess)
{
u64 u;
if (endianess)
{
for(size_t x = 0; x < sizeof(u); x++)
{
u.b[sizeof(u) - x - 1] = arr[x];
}
}
else
{
for(size_t x = 0; x < sizeof(u); x++)
{
u.b[x] = arr[x];
}
}
return u.d;
}
double fooLE(uint8_t *arr)
{
return toDoubleLE(arr, 0);
}
double foobE(uint8_t *arr)
{
return toDoubleLE(arr, 1);
}
compilers are "smart" and x86-64 will convert it to 2 machine code operations.
fooLE:
movzx eax, BYTE PTR [rdi]
movq xmm0, rax
ret
foobE:
mov rax, QWORD PTR [rdi]
bswap rax
movq xmm0, rax
ret
Upvotes: 1
Reputation: 1
Nevertheless, is there a more reliable way to decode a double from or encode it to a 64bit IEEE 754 double-precision floating point
On POSIX or Unix systems, connsider using XDR or ASN/1.
If the data is not too big, consider JSON (e.g. with Jansson) or perhaps YAML and decide to represent it in textual form. Read then carefully the documentation of fscanf and fprintf (e.g. related to %a
format specifier).
See also the floating-point-gui.de
Upvotes: 0