views:

78

answers:

4

Hi Stackoverflow,

I have a function from an external source that returns an array of 2 uint16_t elements (which I cast to int).

I have already been able to cast these to one "big" int ((i1 << 16) + i2)

Now I need to be able to cast this to float, keeping the point value as is in memory.

Can anyone suggest a way or point me in the right direction?

Thanks in advance!

A: 

Perhaps something like this would work?

uint32_t a = ....; // Contains your big int.
float b = *(float*)&a;

Of course that would require you to know int has the same size as float...

Piotr Kalinowski
Although this works on my laptop, the endresult should work not only for this architecture, although I can, when the time comes to use the end device, check whether or not sizeof(float) == sizeof(int). However: Is there no other way of doing this?
cpf
Even, if you use memcpy, the whole re-interpretation will not make sense, unless float has exactly those 32 bits.
Piotr Kalinowski
I include `sizeof()` more as a security measure (ha, stackoverflow!) than as a way of making sure the data comes in ok - byteordering hasn't been mentioned yet but will be the next hurdle...
mvds
I wasn't thinking about security really, but rather issues like: I've filled first 32-bits of 64-bit float. Hmm, that is not going to give the right value, is it? BTW: I guess we could agree float will not be smaller than those 32 bits.
Piotr Kalinowski
yep, this is totally unreliable and 100% non-portable, but a stackoverflow can always be prevented.
mvds
+5  A: 

I suggest to keep very clear that you are messing around and use a memcpy:

float a;
int b;

memcpy(&a,&b,min(sizeof(a),sizeof(b)));

someone might encounter your code when you're long gone, in which case this will show there's something special happening intentionally.

mvds
For the record: you should consider byteordering as well, but that's more of an issue between the platforms talking to eachother. Google for `htons`, `htonl` and friends to get an idea.
mvds
+1 .. best method this one. As a bonus every compiler I've used compiler will even optimise out the memcpy for you :D
Goz
A: 

It depends on what you mean:

uint16_t *ip = external_source();
float f = *(float *)ip;

It could also mean:

uint16_t *ip = external_source();
uint32_t  iv = ((uint32_t)ip[0] << 16) | ip[1];
float      f = iv;

Or you could have some other interpretation in mind. The first assumes that the bits in the array are in the correct sequence to be interpreted as a float. But you need to explain what conversion you require more clearly.

Jonathan Leffler
I know they're not in the correct format: it's more like the second example
cpf
+2  A: 

I'd use a union:

union fltconv {
    float f;
    uint32_t i;
} u;
u.i = ((uint32_t) i1 << 16) | i2;
float f = u.f;

It's more explicit about what you're doing. Bear in mind that this is very nonportable.

Eric Brown
I think it is elegant, but the action is even more spooky, especially for the untrained eye, which will think `u` is a struct.
mvds
If I use an union, which indeed seems elegant, the way to port this in the future would probably be to adjust the uint32_t to the required number of bits (And underlying logic to convert it correctly?)
cpf
+1 because it's the only answer yet that does not break the strict aliasing rules. Casting to float might not survive the optimizer.
Luther Blissett
@Luther, it is as undefined as pointer punning due to the rule mandating that only the last field written should be read.
AProgrammer
just wondering: can you *rely* on the overlap in memory of the union members? i.e. is it a feature? e.g. structs may have holes in them in memory, solved by things like `#pragma pack` iirc
mvds
why not union together a float and a struct of 2 uint16_t? saves you the shifting magic.
mvds
You could union together a float and a struct of 2 uint16_t, _but_ you have more problems - packing and byte order. It would be even less portable than the union, as packing varies across compilers, and floating point typically varies across machines.
Eric Brown