简体   繁体   中英

Parse four bytes to floating-point in C

How do I take four received data bytes and assemble them into a floating-point number?

Right now I have the bytes stored in an array, which would be, received_data[1] ... received_data[4] . I would like to store these four bytes as a single 32-bit single precision float .

-Thanks

I'm actually receiving a packet with 19 bytes in it and assembling two sets of four bytes to make two floating-point numbers. So received_data[1] to received_data[4] is one float, and received_data[5] to received_data[8] is the other...

*UPDATE:**** **More Info...
The first bit , or the sign bit of the float , is the seventh bit the the first byte , here's what I did to check...

#define CHECK_BIT(var,pos) ((var) & (1<<(pos)))  


if( CHECK_BIT(received_data[1], 7))  //set or clear LED2
          {LATAbits.LATA2=1;}else{LATAbits.LATA2=0;}  
if( CHECK_BIT(received_data[5], 7))  //set or clear LED3
          {LATAbits.LATA3=1;}else{LATAbits.LATA3=0;}  

I then checked this by sending alternating positive and negative numbers from my data source, which should have changed the LED's accordingly and it worked.

As long as all that holds true, that means the bytes are in the right order, but they are stored little-endian, correct? Will this be stored into the float in the right order? I haven't had any luck parsing the bytes and reading it as a float yet...

If anyone has any experience with it, I'm using the C18 MPLAB IDE compiler.

FINAL UPDATE:
I have my application running! Just some minor bug fixes now!

THANKS!

Thanks for all the help guys! I'm new to stackoverflow, but this community on here is truly awesome! And a tool like this is truly priceless! I can not even begin to tell you how much time and frustration you have all saved me!

You need to be sure the byte order is correct. Either

float f1 = *(float*)(received_data+1)
float f2 = *(float*)(received_data+5)

or if you have to reverse the bytes, you'll have to copy, so here's an alternative:

union {
  char chars[4];
  float f;
} u;

for (i = 0; i < 4; i++)
  u.chars[3-i] = received_data[i+1];
float f1 = u.f;     
// ... and similarly for second float

It had better be the case that these bytes were written by something like the inverse of this process (either you took the address of a float and cast it to char * or you had a union of char[4] and `float'.)

Assuming they're of the right format already:

float f = *((float*)(&received_data[1]));

Make sure you don't mean received_data[0] . I've left it as one in case you have a filler byte.

How about just copying the data via memcpy?

inline float FloatFromByteArray (const unsigned char * received_data)
{
  float f;
  memcpy (&f, received_data, sizeof (float));
  return f;
}

It copies the data starting at received_data[0]. If you want to copy from received_data[1] just add the offset inside memcpy.

inline float FloatFromByteArray (const unsigned char * received_data)
{
  float f;
  memcpy (&f, received_data+1, sizeof (float));
  return f;
}

You could assemble them in an order that depends on the endianness of your machine, then cast to a float* , and use that pointer to access them.

You would usually but the also put them in data[0] ... data[3] . So...

char *data;

//Assemble in the *right* order
data[0] = received_data[4]; // index is machine dependant!
...

// cast
float *fptr = (float *)data;
printf ("%f\n",*fptr);

From your edit, perhap you should just dump this stuff into a struct :

struct packet_s {
   char byte0;
   float f1;
   float f2;
   ...
}

Then just read (2) or whatever directly into the struct. This method has been discussed on SO before. For instance:

This is how I buffer a float:

static char* bufferFloat    (int* bLen, float value) {
*bLen = sizeof(float);
char* buf = malloc (*bLen);
int storage;

memcpy (&storage, &value, sizeof (int));
uint32_t val = htonl (storage);
memcpy (buf, &val, *bLen);

return buf;
}

This is how I receive a float:

static float readFloat (char* buf, int* bLen) {
float ret;
int temp;

if (*bLen < sizeof (float)) {
    *bLen = 0;
    return 0.0f;
}

memcpy (&temp, buf, sizeof (int));
uint32_t val = htonl(temp);
memcpy (&ret, &val, sizeof (float));
*bLen = sizeof (float);

return ret;
}

This is apart of some hobby networking code i wrote. I hope it helps and it seems to work perfectly for me. :D

Actually, if you want that networking code go here: http://cgi.cse.unsw.edu.au/~robertm /myProjects.php and find the right project.

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