tags:

views:

585

answers:

5

I have this bit of code that is outputting the wrong results.

#include <stdio.h>
#include <string.h>

int main() 
{
  unsigned char bytes[4];
  float flt=0;

  bytes[0]=0xde;
  bytes[1]=0xad;
  bytes[2]=0xbe;
  bytes[3]=0xef;

  memcpy( &flt, bytes, 4);

  printf("bytes 0x%x float %e\n", flt, flt);
  return 0;
}

the output that I get is

bytes 0xc0000000 float -2.000001e+00

I am expecting to get

bytes 0xdeadbeef float -6.2598534e+18

edit #1 as was pointed out the endianness could be different which would result in the following

bytes 0xefbeadde float -1.1802469e+29

what I don't understand is the cast from float to unsigned int resulting in 0xc0000000 (the float in the same printf statement being -2.0000 I would attribute to compiler optimization)

this was working before on a different computer. It could be an architecture change.

+6  A: 

You do realise that floats are promoted to double when passed to a variable parameters function like printf()? So when you say:

printf("bytes 0x%x float %e\n", flt, flt);

you are trying to treat what is really two 8-byte values like two 4-byte values, giving (I believe) undefined behaviour.

anon
+8  A: 

It is not problem of memcpy.

  1. float is allways converted to double when passed over ... of printf, so you just can't get 4 bytes on most of intel architectures.
  2. when you expacting 0xdeadbeef in this code, you assume that your architecture is BIG endian. There are many little endian architectures, for example Intel x86.
Artyom
did not realize that it was a printf issue for the hex portion. I don't understand how the float was not cast properly into a double.
Tanj
Casting float to double is more than shifting four bytes to the right: the conversion makes sure 3.14 in float means 3.14 in double. And after a promotion to double, printf() is passed four bytes, where the %x tells it to expect 2 bytes. So everything after %x is off-base.
Andomar
+2  A: 

The "%x" in printf expects an unsigned int. You're giving it a float which is getting automatically converted and that's not what you want. You want to do something like:

printf("bytes 0x%x float %e\n", *((unsigned int *)&flt), flt);

Oh, and as someone else pointed out, if you're on x86 you're not going to see 0xdeadbeef, more like 0xefbeadde.

btmorex
+1  A: 

See if this is any better:

printf("bytes 0x%x float %e\n", *(int *)&flt, flt);
Artelius
+1  A: 

To see the parameter promotion, change the declaration from float to double. On my machine, that prints:

bytes 0xefbeadde float -1.860545e+230

The 0xefbeadde is big-endian for deadbeaf. The last 4 bytes of the double are undefined, so the number displayed after float will vary.

You mentioned it worked on another computer, what kind of computer was that? Must've been small endian where sizeof(float) == sizeof(double) :)

Andomar