2

I need to write an IEEE single-precision floating point number to a 32-bit hardware register at a particular address. To do that, I need to convert a variable of type float to an unsigned integer. I can get the integer representation like this:

float a = 2.39;
unsigned int *target;
printf("a = %f\n",a);
target = &a;
printf("target = %08X\n",*target);

which returns:

a = 2.390000
target = 4018F5C3

All good. However this causes a compiler warning "cast.c:12: warning: assignment from incompatible pointer type"

Is there any other way to do this which doesn't generate the warning? This is for specific hardware, I don't need to handle different endianness etc and I don't want to loop through each char for performance reasons as some other questions tend to suggest. It seems like you might be able to use reinterpret_cast in C++ but I am using C.

mc_electron
  • 1,503
  • 3
  • 11
  • 13

4 Answers4

5

You can use type punning with a union,

union {
    float f;
    uint32_t u;
} un;
un.f = your_float;
uint32_t target = un.u;

to get the bits. Or you can use memcpy.

Daniel Fischer
  • 181,706
  • 17
  • 308
  • 431
1

You could creat a union type that contains a float and an unsigned int, store a value into the float member, then read it out of the int, like so:

union reg_val
{
  float f_val;
  unsigned int i_val;
} myRegister;
myRegister.f_val = 2.39;
printf("target = %08X", myRegister.i_val);
hair raisin
  • 2,618
  • 15
  • 13
0

If you're trying to simply display the integral value of the float as it's stored in memory, then try using a union:

union {
    float a;
    unsigned int target;
} u;

Store the float value:

u.a = 2.39;

Print both float and integer values:

printf ("a = %f\n", u.a);
printf ("target = %08X\n", u.target); /* you could use %u to show decimal */

No compiler warnings. I use GNU compiler (gcc) on Linux. Notice that target is not a pointer; this is the beauty (and hideousness) of unions. ;-)

pr1268
  • 1,176
  • 3
  • 9
  • 16
0

EDIT: The union solution works everywhere I have tried it but somewhere on SO I had been pointed at standards that showed it didnt have to work. See the link below in the comments to find a LOT more info on this (Thank you Daniel!). Supposed to work or not supposed to work I would use it with care, I imagine endianness, etc gets involved as well (doubles broken into bytes, etc).

Another solution is a dummy asm function. For example on arm:

.globl echo 
echo:
   bx lr


unsigned int echo ( float );
...
unsigned int ra; float f;
f=1.0;
ra=echo(f);

some disassembly is required, needs to be on a system that doesnt have an fpu and/or uses gprs for carrying around floats.

memcpy as already mentioned is the cleanest and most reliable and portable solution (be aware of endianness).

old_timer
  • 69,149
  • 8
  • 89
  • 168
  • 1
    Unless it's been changed since the last draft, footnote 95 in 6.5.2.3 says "If the member used to read the contents of a union object is not the same as the member last used to store a value in the object, the appropriate part of the object representation of the value is reinterpreted as an object representation in the new type as described in 6.2.6 (a process sometimes called ‘‘type punning’’). This might be a trap representation.", so it's officially supposed to work. (Okay, footnotes are informative only, so it's not explicitly _required_ to work). – Daniel Fischer Jul 24 '12 at 20:47
  • 1
    @DanielFischer: The n1124 draft doesn't seem to have that footnote (or I missed it). Section 6.2.6.1.7 seems to contract this: "When a value is stored in a member of an object of union type, the bytes of the object representation that do not correspond to that member but do correspond to other members take unspecified values." The warning is reiterated in Appendix J.1, which claims that the following are unspecified: "The value of a union member other than the last one stored into (6.2.6.1)" – sfstewman Jul 24 '12 at 20:54
  • 1
    Ah, I spoke of n1570 (C11). Sorry for not mentioning that. – Daniel Fischer Jul 24 '12 at 20:57
  • 1
    @DanielFischer: I find this confusing enough to pose it as a question: http://stackoverflow.com/questions/11639947/is-type-punning-through-a-union-unspecified-in-c99-and-has-it-become-specified. Perhaps you can shed light? – sfstewman Jul 24 '12 at 22:02