Compile time/macro swap of endian-ness of float in c99
OP has other problem with using "reverse" float
as a float
A local variable of type float
encoding the "reverse" endian floating point value cannot certainly be initialized as a float
. Many of the values in reverse byte order would correspond to a Not-A-Number (NAN) in the local float
. The assignment may not be stable (bit pattern preserving). It could be:
// not a good plan
float f1 = some_particulate_not_a_number_bit_pattern;
float f2 = some_other_particulate_not_a_number_bit_pattern;
Instead the local "reversed" endian float
should just be a uint32_t
, 4-byte structure/union or 4-byte array initialized in some way with a float
.
// Demo of why a reversed `float` can fail
// The Not-a-numbers bit to control signaling NaN vs. quiet NaN isn't certainly preserved.
int main(void) {
for (;;) {
union {
int32_t i32;
int32_t u32;
float f;
} x,y;
x.i32 = rand();
y.f = x.f;
if (x.u32 ^ y.u32) {
// If bit pattern preserved, this should never print
// v-------+---- biased exponent max (NaN)
// |-------|v--- signaling/quiet bit
// On my machine output is always x1111111 1?xxxxxx xxxxxxxx xxxxxxxx
printf("%08x\n", (unsigned) x.u32);
printf("%08x\n\n", (unsigned) y.u32);
}
}
}
Output
7f8181b1
7fc181b1
...
The below uses a compound literal to meet OP's goal. First initialize a union's float
member with the desired float
. Then extract it byte-by-byte from its uint8_t
member (per desired endian) to initialize a new compound literal's uint8_t
array member. Then extract the uint32_t
. Works for local variables.
#include <stdint.h>
#include <stdio.h>
typedef uint32_t float_reversed;
typedef union {
uint8_t u8[4];
float_reversed u32;
float f;
} endian_f;
#define ENDIAN_FN(_f,_n) ( (endian_f){.f=(_f)}.u8[(_n)] )
#define ENDIAN_F(_f) ((endian_f){ \
ENDIAN_FN(_f,3), ENDIAN_FN(_f,2), \
ENDIAN_FN(_f,1), ENDIAN_FN(_f,0)}.u32)
void print_hexf(void *f) {
for (size_t i=0; i<sizeof f; i++) {
printf("%02X", ((unsigned char *)f)[i]);
}
puts("");
}
int main(void) {
float f1 = 1.0f;
print_hexf(&f1);
float_reversed f1r = ENDIAN_F(f1);
print_hexf(&f1r);
float_reversed f2r = ENDIAN_F(1.0);
print_hexf(&f2r);
}
Output
0000803F
3F800000
3F800000