Question

I have a problem with converting unsigned long to Float single precision Here is my problem

I need to communicate in floating point in my program, but all my internal variables are unsigned long, So the design we decided was such that everything will remain same,(in unsigned long) and once a float needs to be given to application, i will convert to float and pass it on.

So all the variables will have a IEEE 754 bit stream according to

Float converter

Steps i follow :

  1. I get the value in char array
  2. I take the bits and copy into a unsigned long
  3. While giving the data on function call, i typecast to float single precision.

In debugger i see the same bit pattern (in buffers) for steps 1 &2

In step 3 too, i see the same binary pattern, but the value is not interpreted as a float

Input : 21.125

  1. Binary : 01000001101010010000000000000000
  2. Hex : 0x41a90000
  3. Decimal: 1101594624

    Code:
    void ApplicationApi(void * DataPtr)
    {
    (*(float32*)((void*)DataPtr))= unsignedLong_val;
    }
    

Result in application DataPtr * DataPtr = 1.101594624 * e9

Am i missing something here or the type case worked ?

Was it helpful?

Solution

A standard C way to reinterpret the bytes of an unsigned long as a float is:

y = (union { unsigned long u; float f; }) { x } .f;

This code defines a compound literal that is a union, and it initializes the union with the value of x, which should be an unsigned long. Then it accesses the f member of the union, which is a float. This float value is assigned to y, which should be a float.

Thus, assuming the declaration of ApplicationApi must remain the same and that the void *DataPtr it is passed is the result of converting a pointer to a float to a pointer to void, its definition could be:

void ApplicationApi(void *DataPtr)
{
    * (float32 *) DataPtr =(union { unsigned long u; float32 f; }) { unsignedLong_val } .f;
}

Notes about this code:

  • This requires that unsigned long and float32 have the same size.
  • It is undesirable for unsignedLong_val to have file scope. It would be preferable to pass it as a parameter.
  • There is no reason inherent in this code that DataPtr should be passed as a void *. It could be passed as a float32 *.

Notes about code leading up to this code:

  • The way that the bytes have been assembled in the unsigned long may have endian issues.
  • In C implementations that are currently rare, an unsigned long could have trap values that prevent it from being used to hold arbitrary bytes.

About the C standard and reinterpreting bytes:

  • Reinterpreting bytes through a union is the result of C 2011 (N1570) 6.5.2.3 3, which says that an expression using the . operator and a member name has the value of the named member. Note 95 of the standard indicates that this may be used to reinterpret bytes.
  • Another supported way to reinterpret bytes is by converting a pointer to a pointer to a character type and using the new pointer to copy bytes, per 6.3.2.3 7. (memcpy is sometimes used for this.)
  • 6.3.2.3 7 defines this behavior only for pointers to character types. For other types, the C standard generally does not define the behavior of converting a pointer to a pointer of another type and dereferencing the result. Therefore, the behavior of code that does this is undefined. Even if it appears to work in a test, it may later fail due to compiler optimizations or other effects.

OTHER TIPS

Try with this cast :

void ApplicationApi(void * DataPtr)
{
  *(float32*)DataPtr = *(float32*)unsignedLong_val;
}

You have to declare that the right value is a float value.
With your cast, the right value is an integer and the left value a float. The compiler convert implicitly the integer to a float value.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top