views:

515

answers:

3

Ideally the following code would take a float in IEEE 754 representation and convert it into hexadecimal

void convert() //gets the float input from user and turns it into hexadecimal
{
    float f;
    printf("Enter float: ");
    scanf("%f", &f);
    printf("hex is %x", f);
}

I'm not too sure what's going wrong. It's converting the number into a hexadecimal number, but a very wrong one.

123.1443 gives 40000000
43.3     gives 60000000
8        gives 0

so it's doing something, I'm just not too sure what.

Help would be appreciated

+5  A: 

When you pass a float as an argument to a variadic function (like printf()), it is promoted to a double, which is twice as large as a float (at least on most platforms).

One way to get around this would be to cast the float to an unsigned int when passing it as an argument to printf():

printf("hex is %x", *(unsigned int*)&f);

This is also more correct, since printf() uses the format specifiers to determine how large each argument is.

Technically, this solution violates the strict aliasing rule. You can get around this by copying the bytes of the float into an unsigned int and then passing that to printf():

unsigned int ui;
memcpy(&ui, &f, sizeof (ui));

printf("hex is %x", ui);

Both of these solutions are based on the assumption that sizeof(int) == sizeof(float), which is the case on many 32-bit systems, but isn't necessarily the case.

James McNellis
To avoid violationg the strict aliasing rule, try *(volatile unsigned int *)(volatile float *)(
Joshua
Why can't you just printf("hex is %x\n",(unsigned int)f) ???assuming f can fit into unsigned int.
Nyan
@Nyan: Because that won't reinterpret the bits as an unsigned value, that will convert the float to an unsigned value (so, 24.12 would become 24, which isn't the desired outcome).
James McNellis
+4  A: 

When supported, use %a to convert floating point to a standard hexadecimal format. Here is the only document I could find that listed the %a option.

Otherwise you must pull the bits of the floating point value into an integer type of known size. If you know, for example, that both float and int are 32 bits, you can do a quick cast:

printf( "%08X" , *(unsigned int*)&aFloat );

If you want to be less dependent on size, you can use a union:

union {
  float f;
//char c[16]; // make this large enough for any floating point value
  char c[sizeof(float)]; // Edit: changed to this
} u;

u.f = aFloat;
for ( i = 0 ; i < sizeof(float) ; ++i ) printf( "%02X" , u.c[i] & 0x00FF );

The order of the loop would depend on the architecture endianness. This example is big endian.

Either way, the floating point format may not be portable to other architectures. The %a option is intended to be.

drawnonward
+1: I wasn't familiar with the `%a` format specifier. Now I feel dumb :-)
James McNellis
+1 for knowing about %a. Why '`char[16]`' and not '`char[sizeof(float)]`'?
Jonathan Leffler
A: 

How about this:? int main(void){ float f = 28834.38282; char *x = (char *)&f; printf("%f = ", f); for(i=0;i<sizeof(float);i++){ printf("%02X ", *x++ & 0x0000FF); } printf("\n"); }

bliako