8

I have a program that needs to take in 4 bytes and convert them to an IEEE-754 float. The bytes are transferred out of order, but I can put them back in order just fine. My problem is casting them to a float. The relevant parts of code:

//Union to store bytes and float on top of each other
typedef union {
    unsigned char b[4];
    float f;
} bfloat;

//Create instance of the union
bfloat Temperature;

//Add float data using transmitted bytes
MMI.Temperature.b[2] = 0xD1;//MMIResponseMsg[7];
MMI.Temperature.b[3] = 0xE1;//MMIResponseMsg[8];
MMI.Temperature.b[0] = 0x41;//MMIResponseMsg[9];
MMI.Temperature.b[1] = 0xD7;//MMIResponseMsg[10];

//Attempting to read the float value
lWhole=(long) ((float)MMI.Temperature.f);
//DEBUGGING
stevenFloat = (float)MMI.Temperature.f;

lWhole is a long and stevenFloat is a float. When debugging I can see that the values I assign to the byte array are being stored correctly, however the values of stevenFloat and lWhole are incorrect. They seem to hover close to 0, or close to the max float/long values. A long and float are both 32 bits with my compiler.

Does anyone know why this isn't working? It looked correct to me when I received the code to work on and it appears to be a common solution online, I am just stumped.

Steven
  • 285
  • 1
  • 3
  • 11
  • Are you sure they're being transferred out of order? When I put in `0x41d7d1e1` into a hex to float converter, I got ~27, which seems like a nice number. – Drew McGowen Jul 18 '13 at 19:53
  • what would you expect to obtain from `0xD1E141D7`? – triclosan Jul 18 '13 at 19:56
  • That might be my issue, I put those constants in incorrectly. As transferred it would be D1-E1-41-D7 – Steven Jul 18 '13 at 19:56
  • 1
    @H2C03 Confirmed on my machine, swap the bytes in each word (3,2,1,0) and you'll be fine. – IdeaHat Jul 18 '13 at 19:57
  • As a suggestion, create a `bFloat` and explicitly assign the `bFloat::f` value to be the expected value. Then examine `bFloat::b` to see what the actual bytes come out to be, and it may give you the clue you need to fix your problem – Rollie Jul 18 '13 at 20:03
  • Just use `memcpy`. Reading from a union member that hasn't been directly initialized is undefined behavior. – GManNickG Jul 18 '13 at 20:09
  • @GManNickG: It is undefined in C++, but not in C. See http://stackoverflow.com/questions/11639947/ – Nemo Jul 18 '13 at 20:29

1 Answers1

10

Indeed, this is an endianness issue:

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

int main()
{
    union {
        uint8_t bytes[4];
        float f;
    } fun1 = { .bytes = { 0x41, 0xd7, 0xd1, 0xe1} }, fun2 = { .bytes = { 0xe1, 0xd1, 0xd7, 0x41} };

    printf("%f\n%f\n", fun1.f, fun2.f);

    return 0;
}

This prints:

-483860023749617123328.000000
26.977480
  • how did you decide that `-483860023749617123328.000000` is better than `26.977480` – triclosan Jul 18 '13 at 20:01
  • 7
    @triclosan Perhaps because `-483860023749617123328.000000` is a physical impossibility, be it in Celsius, Fahrenheit or Kelvin degrees? –  Jul 18 '13 at 20:03
  • 4
    @H2CO3: Maybe it measures the temperature at the center of the sun in picokelvin... – rodrigo Jul 18 '13 at 20:14
  • Isn't there any other faster and shorter method do the same. This is little ugly if we have several of above and larger arrays to convert. – Dig The Code Dec 11 '17 at 13:52
  • For C++, this results in undefined behavior. I'm not sure whether it is undefined in C. – xskxzr Jun 29 '18 at 12:28