PDA

View Full Version : big/little-endian troubles



Bossa Nova
01-10-2003, 06:29 PM
Hi,

I'm trying to convert a little endian file I'm reading into big endian. All seems to work well except for the floating point function.

float floatSwap(float value)
{
float newValue = 0;
char* pCurVal = (char *)&value;
char* pNewVal = (char *)&newValue;

pNewVal[0] = pCurVal[3];
pNewVal[1] = pCurVal[2];
pNewVal[2] = pCurVal[1];
pNewVal[3] = pCurVal[0];

return newValue;
}

Its not spitting out the right numbers at all.. I know that an IEEE float is stored in some kind of "binary scientific notation" and I kinda think that may be the problem but I can't say for sure. Anybody know what could be wrong?

Coriolis
01-10-2003, 06:46 PM
That function should be right, though I prefer to use unions for this sort of thing:




union
{
byte b[4];
float f;
} src, dst.
cassert(sizeof(src) == sizeof(src.b));
cassert(sizeof(src) == sizeof(src.f));

src.f = value;
dst.b[0] = src.b[3];
dst.b[1] = src.b[2];
dst.b[2] = src.b[1];
dst.b[3] = src.b[0];
return dst.f;


The casserts are just there to catch any compiler issues that may crop up in porting. It is a compile-time assert:




#define cassert(expr) typedef int cassert_typedef[(expr)?1:-1]


If "expr" is false at compile time, it typedefs an array of negative size, which is a compiler error.

GPSnoopy
01-11-2003, 06:27 AM
Don't float registers modify the number representation in some cases? (e.g. when it's not valid or when it's not normalized)

If it's the case, you should avoid using a non-integer type to hold a value that has an incorrect endianess.

You might want to try a type independent function. Something like




void * SwapEndianess (void * p, size_t Size)
{
char * pC = (char *) p;

for (size_t i = 0; i < Size; ++i)
*(pC + i) = *(pC + (Size - 1) - i);

return p;
}


float MyFloat = * ((float *) SwapEndianess(MyBuffer, 4));



But I might be completly wrong.

V-man
01-11-2003, 08:50 AM
>>>>>>
pNewVal[0] = pCurVal[3];
pNewVal[1] = pCurVal[2];
pNewVal[2] = pCurVal[1];
pNewVal[3] = pCurVal[0];
<<<<<<<<

This is not the way to convert from little endian to big or vice versa.
You are simply shuffling bytes around.


Next time, post it in the right group or get flamed.

Bossa Nova
01-11-2003, 09:34 AM
Hey, thanks everybody.

I think your right GPSnoopy. BTW, your code snippet is a very elegant solution. Wish I'd thought of it. As long as I don't ever store any data as a float (until the very end) it should be okay.

btw, V-man--I think you may be confused. My code converts between endians just fine.

Coriolis
01-11-2003, 10:30 AM
Yes, V-Man is confused. Swapping endianness is equivalent to shuffling bytes around.

IEEE 32-bit floats are always stored in 32-bits, by definition; even the illegal values. You can detect an invalid float if the exponent bits (23-30) are all 1. In a nutshell, bit 31 is the sign bit (0 = +, 1 = -), bits 23-30 are the exponent + 127 (so -127 is 0, and +127 is 254), and bits 0-22 are the mantissa with an implicit 1. A denormalized number has a 0 exponent and no implicit 1, if I recall correctly. A 0 is represented by all 0s, except for the sign bit which may be a 0 or a 1 (ie, negative 0 is allowed).

jwatte
01-11-2003, 11:14 AM
Every system I've worked on in the last 15 years have had the htonl() library calls and friends. No need re-inventing the wheel when all the swapping you need is in the library. Assuming, of course, you're not trying to read a little-endian file format on a big-endian platform...