Byte Swapping issue

Started by
6 comments, last by GameDev.net 17 years, 10 months ago
Hi folks.. I'm in a trouble... I'm working on Mac OS and my product has to be universal binary. I'm using Carbon framework and the byte swapping gives me weird results. I'm doing something like this.. ....... Code goes here..... SInt32 test; CFSwappedFloat32 temp; #Ifndef __BIG_ENDIAN__ // swap the bytes test = CFSwapInt32HostToBig(intData); temp = CFConvertFloat32HostToSwapped(floatData); ...... #endif //Write to file I do the reverse swapping while reading the saved file.. The above method works fine if I write file in a PowerPC and read it using same machine. but doesn work if I try to read it using an Intel Mac.. I'm using eMac G4 machine (PowerPC, Mac OS X 10.4.4) Any help will be of great use ...
Advertisement
I don't know the answer, but in addition to your post here you might also try the gdnet *nix forum (I don't know if that would be considered a crosspost), and also idevgames.com. I'm sure that between here and idevgames you can get the info you need.
In C++ you can write this to detect the endianess of a system:
static inlinebool isLittleEndian(){    union U {        int i;        char c;    } u;    u.i = 0x0102;    return u.c == 0x02;}

If optimization is turned on, the compiler will reduce this to a single assembler instruction, depending on if the compilation target is little or big endian (IA32 in this case):
   0:   b8 01 00 00 00          mov    $0x1,%eax   5:   c3                      ret


Then you can use this function to decide on compile-time if conversions are needed. For instance:
int bar(){    int result;    if (isLittleEndian())    {        result = 3;    }    else    {        result = 5;    }    return result;}

compiles down to:
00000000 <bar()>:   0:   b8 03 00 00 00          mov    $0x3,%eax   5:   c3                      ret

Only code for the correct version of endianess is generated.

You can apply this to change network byte order:
unsigned int h2n(unsigned int ui){    enum { N = sizeof(unsigned int) };    union {        unsigned int ui;        unsigned char uc[N];    } u;    u.ui = ui;    if (isLittleEndian())    {        for (int i = 0; i < N/2; i++)        {            unsigned char c = u.uc;            u.uc = u.uc[N-i-1];            u.uc[N-i-1] = c;        }    }    return u.ui;}



Thanks a lot for ur replies...

Now it works fine.. Mistake was with my code.. Again, a silly mistake :)

Thanks again..
static inlinebool isLittleEndian(){    union U {        int i;        char c;    } u;    u.i = 0x0102;    return u.c == 0x02;}

I use a very similar function, it just doesn't have a union.

bool IsLittleEndian(){   int i = 0x01;   char *p = (char *) &i;   return (p[0] == 0x01);}
AP, your compiles down to:
   0:   83 ec 10                sub    $0x10,%esp   3:   b8 01 00 00 00          mov    $0x1,%eax   8:   89 44 24 0c             mov    %eax,0xc(%esp)   c:   31 c0                   xor    %eax,%eax   e:   80 7c 24 0c 01          cmpb   $0x1,0xc(%esp)  13:   0f 94 c0                sete   %al  16:   83 c4 10                add    $0x10,%esp  19:   c3                      ret


The compiler used was GCC:
Using built-in specs.Target: i686-pc-linux-gnuConfigured with: ../gcc-4.1.0/configure --prefix=/home/nmi --enable-languages=c,c++,java --enable-bootstrap --with-x --enable-java-awt=gtk,xlib --enable-gtk-cairoThread model: posixgcc version 4.1.0


As you can see, your version performs the endianess check at runtime, while mine does this at compile time. Having a compile time decision allows the optimiser to remove the dead code.
That's very useful to know and there was me thinking it was an elegant function :(
Thank you nmi.

This topic is closed to new replies.

Advertisement