Fast way to get float from byte array ??
Anubispod
Posts: 42
Hi , i got stuck on some code here , where i receive 4 bytes from serial and have to convert it to float.
The array should be 1.000261 as float.
uint8_t test[4] = {9,236,127,63}; float testme ; printf("Hello World %1.2f \n", testme);I already tried it with mem copy function i found but no luck
The array should be 1.000261 as float.
Comments
That is. test is the address of a byte array. Use a cast (float*) to make it the address of a float.
Dereference that * to get the float value at that address.
The memcpy should have worked, although I think your math is off (those bytes represent 0.999695 as a float). Another, simpler way is to use a union, which lets you represent the same area of memory in two different ways:
(Edit: I see that kuroneko beat me to it!)
1) Endianness issues. If you move your code to a different endian machine it will fail.
2) Padding issues. Possibly your compiler moves things around inside structs ensure some memory alignment.
3) Alignment issues. Moving code to machines that don't like unaligned access can fail. With bus errors or silently.
4) I don't much like the idead of the same thing having multiple names.
I'm sure there are more reasons. But messing up portability due to 1), 2), 3) are the ones I have seen crop up in real world projects most.
I think using the union is the approved way to do it (when it has to be done... as Heater points out it is a dangerous and unportable practice in general, but there are particular times when it has to be done). Dereferencing pointers cast to a different type is more dangerous and does explicitly break aliasing analysis. With a union the compiler at least knows that the memory could be accessed in different ways.
Eric
So, no matter if you use casts or unions the general problem remains.
For this reason we have library functions like htonl(), htons(), ntohl(), ntohs() to convert from host to network byte ordering and back again. They do what ever is required and make your code portable.
Basically, in my opinion, typecasts should be regarded as a directive to the compiler that mean "whatever this is, use it as <type>", but unions say it in a much more structured way "this can be a <type> but it can also be a <type>" (there is no wildcard). My experience is that casts can lead to subtle bugs in cases where the architecture is modified later, and unions are easier to maintain and prevent such bugs to a large extent.
===Jac
Seems though that standard networking code assumes that the structures in its API are in network order and you have to be careful to take care of endianess in your application.
char __attribute__((aligned(4))) testme[4] = {0x8D, 0x08, 0x80, 0x3F}; /* 1.000261, little endian */
XDR is used by NFS RPC and is a good general serialization. See http://en.wikipedia.org/wiki/External_Data_Representation
Anything beyond some primitives is too much for an MCU though.
Heater's notes about htonx() and ntohx() are on the money for me, except that we don't have arpa/inet.h in the library.
A 32 bit Float can be converted using inet.h conversions htonl()/ntohl() in the same way that Spin's F32 operates.
It would be fairly simple to create a set of these conversion function/macros which could be extended to htonf()/ntohf() for 32 bit floats or htond()/ntohd() for 64 bit doubles. Using functions diminish porting problems.
What I'd like is a very simple JSON Marshaller.
It's easier, but not always safe. Casting a pointer to the "wrong" type can confuse the compiler's analysis during optimization. If you're not optimizing, or explicitly turn off alias analysis, it'll be OK. Otherwise it may or may not work. I think the union method should always work.
Anyway, I just tried it in xmmc mode and -O2 and that works too...
Can you think of a simple example that breaks it?
Full example:
Kuroneko provided a good example of how differing alignments for char and float can cause problems. Even if the alignment works out the cast can confuse alias analysis in the optimizer. I don't have an example ready to hand, but gcc's manual warns against this.
Unions fix both of these issues (union alignment is determined by the strictest alignment required for any of its types).
Eric
char __attribute__((aligned(4))) testme[4] = {0x8D, 0x08, 0x80, 0x3F}; /* 1.000261, little endian */
Also, since the data is being treated as a pointer and also cast as a pointer, I don't think there is an optimization issue....
But, say I'm wrong, and there is an optimization issue...
Would marking testme as "volatile" prevent optimization problems?
According to the standard it is OK to access a float via a "char *", but not the other way around.
uint8_t tvSpin::dat[] = {
0x5c, 0x2a, 0xfe, 0xa0, 0x0a,
and then:
Okay = (Cog = (cognew((int32_t)(&(*(int32_t *)&dat[0])), Tvptr) + 1));
The aliasing restrictions added to modern compilers are there so that the compiler is free to optimize properly. There are safe, well-established and standard methods available for converting and re-mapping of all types of variables, casting one type to an incompatible type was something done back in the beginnings of C programming (back in K&R or worse). It's not a good way, and that's why it's not done anymore.
-Tor
That's a bug in spin2cpp. I'm not sure how to work around it, but it's probably one of the reasons spin2cpp generated code doesn't always work properly when optimized. (The problem with volatile variables not being marked is another.)
Eric
Me, I'm into JavaScript now. It faithfully runs what ever whatever line noise I feed it, like the good old days.
I guess the programming language world came full circle.
It doesn't do float, double, structs, or arrays.
If someone wants to contribute those I would be most honored.