My floating value doesn't match my value in C

Viewed 238

I'm trying to interface a board with a raspberry. I have to read/write value to the board via modbus, but I can't write floating point value like the board.

I'm using C, and Eclipse debug perspective to see the variable's value directly. The board send me 0x46C35000 which should value 25'000 Dec but eclipse shows me 1.18720512e+009...

When I try on this website http://www.binaryconvert.com/convert_float.html?hexadecimal=46C35000 I obtain 25,000.

What's the problem?

For testing purposes I'm using this:

int main(){
    
    while(1){ // To view easily the value in the debug perspective 
        float test = 0x46C35000;
        printf("%f\n",test);
    }
    return 0;
}

Thanks!

4 Answers

When you do this:

float test = 0x46C35000;

You're setting the value to 0x46C35000 (decimal 1187205120), not the representation.

You can do what you want as follows:

union {
    uint32_t i;
    float f;
} u = { 0x46C35000 };

printf("f=%f\n", u.f);

This safely allows an unsigned 32-bit value to be interpreted as a float.

You’re confusing logical value and internal representation. Your assignments sets the value, which is thereafter 0x46C35000, i.e. 1187205120.

To set the internal representation of the floating point number you need to make a few assumptions about how floating point numbers are represented in memory. The assumptions on the website you’re using (IEEE 754, 32 bit) are fair on a general purpose computer though.

To change the internal representation, use memcpy to copy the raw bytes into the float:

// Ensure our assumptions are correct:

#if !defined(__STDC_IEC_559__) && !defined(__GCC_IEC_559)
#    error Floating points might not be in IEEE 754/IEC 559 format!
#endif

_Static_assert(sizeof(float) == sizeof(uint32_t), "Floats are not 32 bit numbers");
float f;
uint32_t rep = 0x46C35000;
memcpy(&f, &rep, sizeof f);
printf("%f\n", f);

Output: 25000.000000.

(This requires the header stdint.h for uint32_t, and string.h for memcpy.)

The constant 0x46C35000 being assigned to a float will implicitly convert the int value 1187205120 into a float, rather than directly overlay the bits into the IEEE-754 floating point format.

I normally use a union for this sort of thing:

typedef union xFU
{
    float f;
    uint32_t i;
} FU;

int main()
{
    FU foo;

    foo.f = 25000.0;
    printf("%.8X\n", foo.i);

    foo.i = 0x46C35000;
    printf("%f\n", foo.f);

    return 0;
}

Output:

46C35000
25000.000000

You can understand how data are represented in memory when you access them through their address:

#include <stdio.h>

int main()
{
    float f25000; // totally unused, has exactly same size as `int'
    int i = 0x46C35000; // put binary value of 0x46C35000 into `int' (4 bytes representation of integer)
    float *faddr; // pointer (address) to float
    faddr = (float*)&i; // put address of `i' into `faddr' so `faddr' points to `i' in memory

    printf("f=%f\n", *faddr); // print value pointed bu `faddr'

    return 0;
}

and the result:

$ gcc -of25000 f25000.c; ./f25000
f=25000.000000

What it does is: put 0x46C35000 into int i

copy address of i into faddr, which is also address that points data in memory, in this case of float type

print value pointed by faddr; treat it as float type

you get your 25000.0.

Related