Big Endian and Little Endian

Started by
17 comments, last by GameDev.net 18 years ago
I was trying to swap big-endian and little endian... and wrote this code...I guess this is sufficient...but this is for unsigned types...can you suggest some code for signed types??

inline void endian_swap(unsigned short& x)
{
    x = (x>>8) | (x<<8);
}
Advertisement
Not entirely positive, but assuming 2's complement, signedness shouldn't make a difference.
For little endian anyway, where the first bytes in memory are lower significance, the last byte has the sign bit (for each integer data type and IEEE float type this is true, anyway).

I'm guessing that in big endian, the sign bit is still in the "most significant byte" (which is the first on in that case).

It's probably possible to think of endianness as being "lower level" than signedness.


As for code, you can probably do some clever typecasting to force the compiler to switch signedness. Also, if you're ever manually converting a signed value from a smaller to larger value, you might have to sign-extend it.

(Sign extension means that if the sign bit is 1, fill the 'new' bytes in the larger type with 1s to keep the same value)
Quote:Original post by Anonymous Poster
Not entirely positive, but assuming 2's complement, signedness shouldn't make a difference.


In 2's complement signednes makes a big difference. The OP's code will not work properly with a signed numeric type. The right shift will fill the upper byte with all 1's which will result in incorrect values whenever the lower byte isn't 0xFF. To do an endian swap with a signed type just cast it to unsigned, swap it, and cast it back. The casting can be handled implicitly, but some compilers will spit out warnings if you don't explicitly cast.
Quote:Original post by Troll
The right shift will fill the upper byte with all 1's....


It varies from machine to machine.
In which case it may be more prudent to do something like this:

inline void endian_swap(unsigned short& x){    char * k = reinterpret_cast<char*>(&x);    std::swap(k[0], k[1]);}


Untested, seems right.
[ search: google ][ programming: msdn | boost | opengl ][ languages: nihongo ]
Quote:Original post by Troll
Quote:Original post by Anonymous Poster
Not entirely positive, but assuming 2's complement, signedness shouldn't make a difference.


In 2's complement signednes makes a big difference. The OP's code will not work properly with a signed numeric type. The right shift will fill the upper byte with all 1's which will result in incorrect values whenever the lower byte isn't 0xFF. To do an endian swap with a signed type just cast it to unsigned, swap it, and cast it back. The casting can be handled implicitly, but some compilers will spit out warnings if you don't explicitly cast.


Does the right shift treat signed and unsigned differently? I thought it'd treat them the same, especially because they look exactly the same under 2's complement (i.e. there is a bijection between unsigned int's greater than INT_MAX and signed int's less than 0), which is why we use 2's complement in the first place.
Quote:Original post by _goat
In which case it may be more prudent to do something like this:

*** Source Snippet Removed ***

Untested, seems right.


But..you haven't casted it to unsigned type...or have you??
I know from experience that different compilers, platforms, etc. will behave differently with right shifts on signed integers. Some will sign extend, some will shift in zeroes. The standard says the behavior is implementation defined. In other words, don't rely on it.
SlimDX | Ventspace Blog | Twitter | Diverse teams make better games. I am currently hiring capable C++ engine developers in Baltimore, MD.
Is the above solution provided by _goat valid for signed numbers?

This topic is closed to new replies.

Advertisement