Little Endian to Big Endian

Moderator
Posts: 1,140
Joined: 2005.07
Post: #31
There is not, but you would likely want to typecast to an unsigned int before swapping if you're using shifts, otherwise it will do nasty things with the sign bit.
Quote this message in a reply
Jones
Unregistered
 
Post: #32
akb825 Wrote:There is not, but you would likely want to typecast to an unsigned int before swapping if you're using shifts, otherwise it will do nasty things with the sign bit.

Not *exactly* sure what you mean, but I've got two seperate functions. They both do the same thing, but one with int's and one with unsigned ints. Here they are:

Code:
#define TINY_ENDIAN        8956432
#define HUGE_ENDIAN        8956234


inline void swapUSHORT(unsigned short& swap_this_short)
{
    swap_this_short = (swap_this_short>>8) |
        (swap_this_short<<8);
}


inline void swapSHORT(short& swap_this_short)
{
    swap_this_short = (swap_this_short>>8) |
        (swap_this_short<<8);
}

/*
inline void swapUINT(unsigned int& swap_this_int)
{
    swap_this_int = (swap_this_int>>24) |
        ((swap_this_int<<8) & 0x00FF0000) |
        ((swap_this_int>>8) & 0x0000FF00) |
        (swap_this_int<<24);
}
*/

inline void swapINT(int& swap_this_int) {

swap_this_int = (swap_this_int>>24) |
        ((swap_this_int<<8) & 0x00FF0000) |
        ((swap_this_int>>8) & 0x0000FF00) |
        (swap_this_int<<24);

}

void swapLONG(long swap_this_long)
{
  unsigned char sl_b1, sl_b2, sl_b3, sl_b4;

  sl_b1 = swap_this_long & 255;
  sl_b2 = ( swap_this_long>> 8 ) & 255;
  sl_b3 = ( swap_this_long>>16 ) & 255;
  sl_b4 = ( swap_this_long>>24 ) & 255;

  swap_this_long = ((int)sl_b1 << 24) + ((int)sl_b2 << 16) + ((int)sl_b3 << 8) + sl_b4;
}

void swapFLOAT(float swap_this_float)
{
      union
      {
        float sff;
        unsigned char sfb[4];
      } sf_dat1, sf_dat2;

      sf_dat1.sff = swap_this_float;
      sf_dat2.sfb[0] = sf_dat1.sfb[3];
      sf_dat2.sfb[1] = sf_dat1.sfb[2];
      sf_dat2.sfb[2] = sf_dat1.sfb[1];
      sf_dat2.sfb[3] = sf_dat1.sfb[0];
      swap_this_float = sf_dat2.sff;
}

int getENDIAN()
{
   int ge_i = 1;
   char *ge_p = (char *) &ge_i;
   if (ge_p[0] == 1)
      return TINY_ENDIAN;
   else
      return HUGE_ENDIAN;
}

I included the entire file for a reason, is it ok to do the same with shorts, like I did?

Thanks!
Quote this message in a reply
Luminary
Posts: 5,143
Joined: 2002.04
Post: #33
gah! You and your run-time checks! There is no need for a getENDIAN() function, you already know what it's going to return as you compile your program!

If you wanted to have it, just for debugging, you should still write it as

Code:
int getEndian()
{
#if defined(__BIG_ENDIAN__)
    return HUGE_ENDIAN;
#else
    return TINY_ENDIAN;
#endif
}

Yes, it does matter that you don't byte-swap signed integers with the functions you've written. C makes no guarantee as to whether >> is arithmetic or logical, and Microsoft's compiler at least (don't know about GCC, it could be architecture-specific even) treats it as arithmetic.
Quote this message in a reply
Moderator
Posts: 1,140
Joined: 2005.07
Post: #34
What I mean by shifting and the sign bit is, if the number is a signed integer and is negative, it will try to keep the signed bit a 1 to keep it a negative number. As a result, if your number is negative to begin with (swapped or unswapped), it will be negative afterwards regardless of if it should or should not be negative.

Also, just FYI, for the float, instead of using a union you could also just do this:
unsigned int temp = *(unsigned int *)&swap_this_float;
swapUINT(temp);
swap_this_float = *(float *)&temp;

You can swap doubles the exact same way, but with long longs. BTW, your swapLONG function makes no sense to me... Also, keep in mind that longs are 32 bits on 32 bit machines and 64 bits on 64 bit machines. (on OS X, at least)

Edit: OSC, are the __BIG_ENDIAN__ and __LITTLE_ENDIAN__ flags defined in Microsoft's compiler and others? If it's only defined in gcc, and you want to target other platforms, then you may not be able to rely on compile-time checks.
Quote this message in a reply
Luminary
Posts: 5,143
Joined: 2002.04
Post: #35
__BIG_ENDIAN__ is a GCC thing, but there'll always be an equivalent check for other platforms.

#if defined(__LITTLE_ENDIAN__) || defined(_WIN32)

for example Wink
Quote this message in a reply
Luminary
Posts: 5,143
Joined: 2002.04
Post: #36
The union approach is better than the type-punned-pointer approach, because it doesn't break strict aliasing rules. (-fstrict-aliasing in GCC)
Quote this message in a reply
Jones
Unregistered
 
Post: #37
akb825 Wrote:What I mean by shifting and the sign bit is, if the number is a signed integer and is negative, it will try to keep the signed bit a 1 to keep it a negative number. As a result, if your number is negative to begin with (swapped or unswapped), it will be negative afterwards regardless of if it should or should not be negative.

If it was negative to begin with, wouldn't I want to keep it negative? Do you mean a case where it's not meant to be negative, but a big endian loads as negative from a little endian file because it's all greek as far as it's concerned?

Quote:BTW, your swapLONG function makes no sense to me...

Me neither. I borrowed it from some other code, and never used it. LOL
Quote this message in a reply
Luminary
Posts: 5,143
Joined: 2002.04
Post: #38
(int)0x80000000 >> 24 may be either (int)0xffffff80 or 0x00000080, depending on the compiler's whimsy. If it's the former, you will not get the result you want. (unsigned int)0x80000000 >> 24 is always 0x00000080.
Quote this message in a reply
Moderator
Posts: 1,140
Joined: 2005.07
Post: #39
What I mean by "keeping negative" is if the swapped value, which isn't what you want, is negative, then it will make the final value negative. For example, if the pre-swapped value is 0x80000000, you would expect the final value to be 0x00000080. However, the final value would end up being 0xFFFFFF80 because it extends the signed bit, and you will therefore need to make it unsigned.

The compiler is supposed to use arithmetic shifting if it's a signed value, and logical for an unsigned value. I'm pretty sure that gcc follows that. It's not like it's too difficult to follow, though, seeing that AFAIK they are 2 separate instructions. I guess that it automatically treats hex as an unsigned value, which is why you need to cast it to make it signed..
Quote this message in a reply
Luminary
Posts: 5,143
Joined: 2002.04
Post: #40
No, the compiler is allowed to do whatever it wants for a right shift of a negative signed value:
http://www.open-std.org/JTC1/SC22/WG14/w.../n1124.pdf
(section 6.5.7, paragraph 5)
Quote this message in a reply
Moderator
Posts: 1,140
Joined: 2005.07
Post: #41
Huh, interesting. At least it's consistent with unsigned values. Rasp

Funny, though, saying the section like that reminds me of quoting Star Fleet regulations. Wink
Quote this message in a reply
Jones
Unregistered
 
Post: #42
Ack! I still have no idea what I should do here. I think I'll just make all my ints unsigned, that'll simplify things. Smile
Quote this message in a reply
Jones
Unregistered
 
Post: #43
Jones Wrote:Ack! I still have no idea what I should do here. I think I'll just make all my ints unsigned, that'll simplify things. Smile

Holy... you aren't gonna believe this... but I converted all my ints to uints, and the code works great! (My MD2 class problem is solved!)
Quote this message in a reply
Post Reply 

Possibly Related Threads...
Thread: Author Replies: Views: Last Post
  Endian-ness ia3n_g 11 4,064 Sep 20, 2006 11:47 PM
Last Post: OneSadCookie
  Even *MORE* endian issues Jones 22 6,423 Aug 3, 2006 06:40 PM
Last Post: Jones