What is the struct (binary format) of float datatype in C?

How can I find information about float datatype in C? I mean the bit struct for this type (decimal, signal indicator, etc...)? Let me explain what I'm trying to do:

I am implementing an network protocol and I need to send 6 octects with Latitude and Longitude (according to protocol documentation). First 3 octects must have LAT information and last 3 must have LON information. I can't use bitwise operators in float datatype, so for debug, I'm copying memory of float variable to a new uint32_t variable (both 4-bytes wide) and then, trying to shift bit's to get the correct value, but it's not working.

This is the code that I'm using to test/debug conversion:

    int32_t b = 0;    
    memcpy(&b,&a,4);
    int32_t c = (b >> 23);        
    printf("Valor de C: 0x%X, Decimal: %d\n",c,c);
// Should print only '23', but it's printing 
// Valor de C: 0x41B, Decimal: 1051

After 'knowing' the correct bit-position of float, I'll copy those bit's to my protocol data, which is an array of unsigned char[6] (this I can't change the type, only values).

Any tip's about how to accomplish this? Information abour protocol

Upvotes: 0

Views: 595

Answers (3)

Jean-Marc Volle
Jean-Marc Volle

Reputation: 3333

Here is a sample code showing how to encode the float latitude. (same thing for longitude). See: https://en.wikipedia.org/wiki/Q_(number_format)#Float_to_Q for an introduction to fixed point encoding with 2 complements sign management.

It uses fixed point encoding with weight provided by the specification.

#include <stdio.h>
#include <stdlib.h>
int main()
{

    /* weight of one bit */
    const float weight = 180./(1 << 23);
    printf ("w=%f\n",weight);

    /* a few sample conversions */
    /* 2.53 degres */
    float lat = 2.53; 
    printf ("lat=%f\n",lat);

    int fp_lat = (int) (0.5f + lat / weight);
    printf ("fplat=0x%x\n",fp_lat);

    lat = 180.f; /* +180 degres */
    printf ("lat=%f\n",lat);

    fp_lat = (int) (0.5f+ lat / weight);
    printf ("fplat=0x%6x\n",fp_lat); /*exactly 23 bits */

    /* negative numbers)*/
    lat = -180.f; /* -180 degres */

    printf ("lat=%f\n",lat);

    fp_lat = (int) (0.5f + abs(lat) / weight);
    if (lat <0)
    {
        /*2 complement representation */
        fp_lat = (~fp_lat + 1) & 0xffffff;
    }
    printf ("fplat=0x%6x\n",fp_lat); /* same value as 180 */


    /*sample packing for latitude */
    unsigned char msg[6];
    msg[0] = (unsigned char)((fp_lat >> 16) & 0xff); /* most significant byte of 24 bits*/
    msg[1] = (unsigned char)((fp_lat >> 8 ) & 0xff);
    msg[2] = (unsigned char)((fp_lat      ) & 0xff);

    /* to be continued */
    return 0;

}

Upvotes: 2

KamilCuk
KamilCuk

Reputation: 141523

The interpretation of data is something separate from the data. The unit of the data is something separate from the data itself. So I can say 123 milliseconds or 0.123 seconds or 234 half-milliseconds or 1.23 * 10^-2 seconds and all these forms represent the same "value".

The data you posted I guess is composed of two numbers encoded in twos-complement numbers represented in big endian with most significant bit first.

unsigned char data[6]; // assuming indexes reference octet numbers
// big endian - first byte is the most significant
// I assume the hardware uses twos complement internally 
// the method as described in https://stackoverflow.com/questions/35876000/converting-24-bit-integer-2s-complement-to-32-bit-integer-in-c
int32_t latitude_value = (int32_t)( data[0] << 24 | data[1] << 16 | data[2] << 8 ) / 256;
// latitude_value represents latitude in units of 180/2^23 degrees

Now you can "transform" the latitute from units of 180/2^23 degrees to units of plain degrees if you want to represent it that way:

double latitue_in_degrees = (double)latitude * 180.0 / exp2(23);

Note that there are problems with floating point types.

What is the struct (binary format) of float datatype in C?
How can I find information about float datatype in C?
I mean the bit struct for this type (decimal, signal indicator, etc...)?

The exact format of float type depends on your compiler - it can be anything. Well, an overwhelming majority of systems/compilers today use binary32 format from IEC 754 standard for float datatype. Refer to the standard and endless net resources for the exact format of the datatype. For example this converter is just fun to use.

Upvotes: 1

jbulatek
jbulatek

Reputation: 164

Usually for such purposes bit fields are used. You can try something like this:

#pragma pack(1)
typedef struct {
    union latitude{
        uint32_t value : 24;
        struct octets{
            uint8_t octetOne : 8;
            uint8_t octetTwo : 8;
            uint8_t octetThree : 8;
        }
    }
    union longitude{
        uint32_t value : 24;
        struct octets{
            uint8_t octetOne : 8;
            uint8_t octetTwo : 8;
            uint8_t octetThree : 8;
        }
    }
} frame;

Then store incomming data in this struct and access desired values by: frame.longitude.value etc.

Upvotes: -1

Related Questions