2
union uint64_t_double {
    uint64_t u;
    double d;
};

uint64_t double_to_uint64_t(double d) {
    union uint64_t_double ud;
    ud.d = d;
    return ud.u;
}

double uint64_t_to_double(int64_t u) {
    union uint64_t_double ud;
    ud.u = u;
    return ud.d;
}

Basically, can I convert these two functions to macros?

I need this becaus TinyC does not optimize(inline) functions calls as clang/gcc.

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312
exebook
  • 32,014
  • 33
  • 141
  • 226

1 Answers1

2
#define ReinterpretDoubleAsUint64_t(x) ((union { double d; uint64_t u; }) { x } .u)

#define ReinterpretUint64_tAsDouble(x) ((union { uint64_t u; double d; }) { x } .d)

In C, code “(type) { initializer-list }” is a compound literal. It creates an object with the specified type and initialization. So:

(union { double d; uint64_t u; }) { x }

creates a union that is initialized with x. By default, the first member of the union is initialized, so this is a union in which the double member d has been set to x. Give that union, .u is simply the usual way of referring to a member of a union. So:

(union { double d; uint64_t u; }) { x } .u

is the member u of the union. When a union member other than the last one stored is read, the bytes of the union are reinterpreted in new type. So this reinterprets the bytes of the double as uint64_t.

This is standard C, but it uses implementation-defined behavior (notably, the way double values are encoded depends on the implementation, as does whether double and uint64_t have the same size).

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312