Search code examples
c++ccasting

Separate a float into 4 uint8_ts and then merge back together


I'm working on developing both the client(C) and server(C++) side of an RF connection. I need to send a float value, but the way the architecture is set up I have to arrange my message in a struct that limits me to 3 uint8t parameters: p0, p1, p2. My solution was to break the float into an array of 4 uint8_ts and send in 2 separate messages and use p0 as an identifier whether the message contains the first or second half.

So far I have something like this:

Server (C++):

sendFloat(float f)
{
   messageStruct msg1, msg2;
   uint8_t* array = (uint8_t*)(&f);

   msg1.p0 = 1; //1 means it's the first half
   msg1.p1 = array[0];
   msg1.p2 = array[1];

   msg2.p0 = 0; //0 means it's the second half
   msg2.p1 = array[2];
   msg2.p2 = array[3];

   sendOverRf(msg1);
   sendOverRf(msg2);
}

Client(C):

processReceivedMessage (uint32_t id, uint32_t byteA, uint32_t byteB) //(p0,p1,p2) are routed here
{
   static uint32_t firsHalfOfFloat;
   uint32_t ondHalfOfFloat;
   float combinedFloat;
   
   if(id == 1) //first half
   {
       firstHalfOfFloat = (byteA << 8) | byteB;
   }
   else        //second half
   {
       secondHalfOfFloat = (byteA << 8) | byteB;
       combinedFloat = (float)((firstHalfOfFloat << 16) | secondHalfOfFloat);
   }
  
    writeFloatToFile(combinedFloat);
}  

then on request the client must then send that float back

Client(C):

sendFloatBack(uint8_t firstHalfIdentifier) // is commanded twice by server with both 0 and 1 ids
{
    messageStruct msg;
    float f = getFloatFromFile();
    uint8_t* array = (uint8_t*)(&f);
    
    msg.p0 = firstHalfIdentifier;

    if(firstHalfIdentifier == 1) //First half
    {
        msg.p1 = array[0];
        msg.p2 = array[1];       
    }
    else                         //Second half
    {
        msg.p1 = array[2];
        msg.p2 = array[3];  
    }
    
    sendOverRf(msg);
}

and finally the Server (C++) gets the value back:

retrieveFunc()
{
    float f;
    uint32_t firstHalf;
    uint32_t secondHalf;
        
    messageStruct msg = recieveOverRf();
    firstHalf = (msg.p1 << 8) | msg.p2;
    msg = receiveOverRf();
    firstHalf = (msg.p1 << 8) | msg.p2;
    f = (firstHalf << 16) | secondHalf;  
}

but I'm getting really wrong values back. Any help would be great.


Solution

  • Unions are a very convenient way to disassemble a float into individual bytes and later put the bytes back together again. Here's some example code showing how you can do it:

    #include <stdio.h>
    #include <stdint.h>
    
    typedef union {
       uint8_t _asBytes[4];
       float   _asFloat;
    } FloatBytesConverter;
    
    int main(int argc, char** argv)
    {
        FloatBytesConverter fbc;
        fbc._asFloat = 3.14159;
    
        printf("Original float value is:  %f\n", fbc._asFloat);
    
        printf("The bytes of the float are:  %u, %u, %u, %u\n"
           , fbc._asBytes[0]
           , fbc._asBytes[1]
           , fbc._asBytes[2]
           , fbc._asBytes[3]);
    
        // Now let's put the float back together from the individual bytes
        FloatBytesConverter ac;
        ac._asBytes[0] = fbc._asBytes[0];
        ac._asBytes[1] = fbc._asBytes[1];
        ac._asBytes[2] = fbc._asBytes[2];
        ac._asBytes[3] = fbc._asBytes[3];
    
        printf("Restored float is %f\n", ac._asFloat);
    
        return 0;
    }