3

How can we print the encoding of a floating-point value in C? I know I can use %A, but that isn't the format I want.

For example, if my value is 1.3416407, I want to print ”0x3FABBAE2“, I do not “0X1.5775C4P+0”.

Eric Postpischil
  • 168,892
  • 12
  • 149
  • 276
Veridian
  • 3,450
  • 11
  • 42
  • 77
  • 2
    I applaud you wanting `0x` as the prefix and upper-case A-F for the hex digits. Be aware that the standard doesn't make that easy; you have to code the format explicitly (`"0x%.8X"`, for example). If you use `%X`, you get 0X as the prefix but A-F for the digits; if you use `%x`, you get 0x as the prefix but a-f for the digits. – Jonathan Leffler Jul 15 '13 at 22:05

4 Answers4

4

You can use a union, e.g.

#include <stdio.h>
#include <stdint.h>

union {
    float f;
    uint32_t i;
} u;

u.f = 1.3416407f;
printf("%#X\n", u.i);
Paul R
  • 202,568
  • 34
  • 375
  • 539
  • 1
    THANK YOU! I COULDN'T FIND THIS ANYWHERE! – Veridian Jul 15 '13 at 21:52
  • not that it matters, but I think the max number of digits in a floating point is `6`. +1 for using a 32-bit integer instead of `int` – tay10r Jul 15 '13 at 21:52
  • 1
    @Taylor Flores, 6 is likely from FLT_DIG "number of decimal digits, q, such that any floating-point number with q decimal digits can be rounded into a floating-point number with p radix b digits and back again without change to the q decimal digits,". So if you are round-tripping, 6 is OK. If you want "max number of digits" it needs a more precise definition. You would need to do a "%.7e" to printf() all floats distinctly. – chux - Reinstate Monica Jul 15 '13 at 22:32
2

The union idea present by @Paul R is good but would benefit with refinements

union {
    float f;
    uint32_t i;
} u;

u.f = 1.3416407f;
printf("0x%08" PRIX32 "\n", u.i);

This insures 8 hexadecimal characters are printed, zero padding as needed. It also matches the sizeof(u.i) should it differ from sizeof(int).

Though it does suffer should from the uncommon sizeof(float) != sizeof(uint32_t);

chux - Reinstate Monica
  • 127,356
  • 13
  • 118
  • 231
1

You can walk the type octet by octet:

float f = 1.3416407;
unsigned char *fp = (void *)&f;
size_t i;
printf("0x");
for (i = 0; i < sizeof(float); ++i) {
    printf("%02X", fp[i]);
}
puts("");

You may need to print the octets in reverse order depending on the desired endianess.

jxh
  • 66,730
  • 7
  • 105
  • 179
1

To print the hexadecimal presentation of an arbitrary thing, use

union {
    arbitrary object;
    unsigned char bytes[sizeof (arbitrary)];
} u;

I.e.

union {
    float object;
    unsigned char bytes[sizeof (float)];
} u;

u.object = 1.3416407f;
printf("0x");
for (size_t i = 0; i < sizeof(u.bytes); i++) {
    printf("%02hhx", u.bytes[i]);
}
printf("\n");

Or to reverse the bytes for little endian:

printf("0x");
for (size_t i = sizeof(u.bytes) - 1; i < sizeof(u.bytes); i--) {
    printf("%02hhx", u.bytes[i]);
}
printf("\n");

The code above assumes that CHAR_BIT == 8.

chux - Reinstate Monica
  • 127,356
  • 13
  • 118
  • 231