Sign in to follow this  
KumGame

Byte Swapping issue

Recommended Posts

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 ...

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
In C++ you can write this to detect the endianess of a system:

static inline
bool 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.

Share this post


Link to post
Share on other sites
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[i];
u.uc[i] = u.uc[N-i-1];
u.uc[N-i-1] = c;
}
}

return u.ui;
}



Share this post


Link to post
Share on other sites
Guest Anonymous Poster

static inline
bool 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);
}

Share this post


Link to post
Share on other sites
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-gnu
Configured 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-cairo
Thread model: posix
gcc 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.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
That's very useful to know and there was me thinking it was an elegant function :(
Thank you nmi.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this