简体   繁体   中英

Converting 4 raw bytes into 32-bit floating point

I'm trying to re-construct a 32-bit floating point value from an eeprom.

The 4 bytes in eeprom memory (0-4) are : B4 A2 91 4D

and the PC (VS Studio) reconstructs it correctly as 3.054199 * 10^8 (the floating point value I know should be there)

Now I'm moving this eeprom to be read from an 8-bit Arduino, so not sure if it's compiler/platform thing, but when I try reading the 4 bytes into a 32-bit dword, and then typecast it to a float, the value I get isn't even close.

Assuming the conversion can't be done automatically with the standard ansi-c compiler, how can the 4 bytes be manually parsed to be a float?

The safest way, and due to compiler optimization also as fast as any other, is to use memcpy :

uint32_t dword = 0x4D91A2B4;
float f;
memcpy(&f, &dw, 4);

Demo: http://ideone.com/riDfFw

As Shafik Yaghmour mentioned in his answer - it's probably an endianness issue, since that's the only logical problem you could encounter with such a low-level operation. While Shafiks answer in the question he linked, basically covers the process of handling such an issue, I'll just leave you some information:

As stated on the Anduino forums, Anduino uses Little Endian . If you're not sure about what will be the endianness of the system you'll end up working on, but want to make your code semi-multiplatform, you can check the endianness at runtime with a simple code snippet:

bool isBigEndian(){
   int number = 1;
   return (*(char*)&number != 1);
}

Be advised that - as all things - this consumes some of your procesor time and makes your program run slower, and while that's nearly always a bad thing, you can still use this to see the results in a debug version of your app.

How this works is that it tests the first byte of the int stored at the address pointed by &number . If the first byte is not 1 , it means the bytes are Big Endian .

Also - this only will work if sizeof(int) > sizeof(char) .

You can also embed this in your code:

float getFromEeprom(int address){
   char bytes[sizeof(float)];
   if(isBigEndian()){
      for(int i=0;i<sizeof(float);i++)
         bytes[sizeof(float)-i] = EEPROM.read(address+i);
   }
   else{
      for(int i=0;i<sizeof(float);i++)
         bytes[i] = EEPROM.read(address+i);
   }
   float result;
   memcpy(&result, bytes, sizeof(float));
   return result;
}

You need to cast at the pointer level.

int     myFourBytes = /* something */;
float*  myFloat = (float*) &myFourBytes;
cout << *myFloat;

Should work.

If the data is generated on a different platform that stores values in the opposite endianness, you'll need to manually swap the bytes around. Eg:

unsigned char myFourBytes[4] = { 0xB4, 0xA2, 0x91, 0x4D };
std::swap(myFourBytes[0], myFourBytes[3]);
std::swap(myFourBytes[1], myFourBytes[2]);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM