Jump to content


Endianness conversion of data


19 replies to this topic

#1 NomadRock

    Senior Member

  • Members
  • PipPipPipPip
  • 785 posts

Posted 17 September 2004 - 08:26 AM

unsigned int convertEndianness(unsigned int data) {
 char * c;
 char temp;
 unsigned int test = 0x000000FF;

 if((char*)(&test)[0] == (char)(0xFF)) // this machine is little endian
 {
  c = (char*)(&data);
  temp = c[0];
  c[0] = c[3];
  c[3] = temp;
  temp = c[1];
  c[1] = c[2];
  c[2] = temp;
 }
 return data;
}

When programming across networks it is often necessary to transfer data between a machine that is little endian and a machine that is big endian. See the Wikipedia entry for more information on the subject.

Generally network transmission should be in big endian. This function will prep data for sending across the network and do the reverse for data recieved across the network. This way the endianness of the opposite machine does not matter. First it checks to see if the first byte is the same as the least significant byte. If this is the case then the machine is little endian and the data must be converted.
Jesse Coyle

#2 Nick

    Senior Member

  • Members
  • PipPipPipPip
  • 1227 posts
  • LocationOttawa, Ontario, Canada

Posted 17 September 2004 - 11:09 AM

Nice trick to automatically compile for the endianness of the local machine!

There's an x86 instruction for swapping endianness quickly: bswap.

#3 davepermen

    Senior Member

  • Members
  • PipPipPipPip
  • 1306 posts

Posted 17 September 2004 - 11:23 AM

cool. never noticed this one :D
davepermen.net
-Loving a Person is having the wish to see this Person happy, no matter what that means to yourself.
-No matter what it means to myself....

#4 NomadRock

    Senior Member

  • Members
  • PipPipPipPip
  • 785 posts

Posted 17 September 2004 - 01:23 PM

I basically never use assembly so I didn't know about that, but the whole point of the function was to be as portable as possible, I figure if I don't know the endianness of the machine I probably wont know the archetecture either. You are right though, if this is used in a performance critical location it is better to sacrifice readability in order to put in multiple code paths in so you can use the assembly of each architecture. The apps I was writing were not proccessor bound on network transmission though, so I didn't have to worry about optomization. :)
Jesse Coyle

#5 Michael

    Member

  • Members
  • PipPip
  • 67 posts

Posted 17 September 2004 - 01:55 PM

You could also simply use htonl and the likes.

#6 freak0r

    New Member

  • Members
  • Pip
  • 1 posts

Posted 17 September 2004 - 05:51 PM

c = (char*)(&data);
if(c[0] == (char)(data % 256)) // this machine is little endian

I don't think thats a good idea. Think about a value like 0xFFABCDFF. The above code will determine the 'machine' to be little endian, although it doesn't necessary need to be. You basically compare the first byte of the value with the total value modulo 256. This will lead to potentially wrong results if the first and last byte are identical.

Or am I missing the obvious?? It's still early morning :)

#7 Michael

    Member

  • Members
  • PipPip
  • 67 posts

Posted 17 September 2004 - 08:16 PM

No, I think that's a bug. You should do the check on some known data, such as:
bool isLittleEndian() { int foo=1; return 1==*((char*)&foo); }

Or just use htonl etc...

#8 NomadRock

    Senior Member

  • Members
  • PipPipPipPip
  • 785 posts

Posted 17 September 2004 - 08:46 PM

There is an error in the code but that is not it. I modulus by 256 to zero out the other bytes, but this would not work if the lower byte is zero already. I will fix the code to accomidate this.
Jesse Coyle

#9 NomadRock

    Senior Member

  • Members
  • PipPipPipPip
  • 785 posts

Posted 17 September 2004 - 08:54 PM

I suppose even better I could use
#define LITTLE_ENDIAN ((0xFF000000 >> 24) & (255))

Jesse Coyle

#10 Michael

    Member

  • Members
  • PipPip
  • 67 posts

Posted 17 September 2004 - 09:10 PM

NomadRock said:

I suppose even better I could use
#define LITTLE_ENDIAN ((0x000000FF << 24) & (0xFF000000))

View Post

No.

#11 NomadRock

    Senior Member

  • Members
  • PipPipPipPip
  • 785 posts

Posted 17 September 2004 - 09:40 PM

Ok, what is wrong with that?
Jesse Coyle

#12 Michael

    Member

  • Members
  • PipPip
  • 67 posts

Posted 17 September 2004 - 09:42 PM

It doesn't return 0 for big endian machines.

#13 NomadRock

    Senior Member

  • Members
  • PipPipPipPip
  • 785 posts

Posted 17 September 2004 - 10:44 PM

Quite true, good catch. Corrected as such. I really wish I didn't have to worry too much about the low level, but it is a good learning experience. Hopefully others can learn from this too.

BTW, I checked up on htonl, this is basically what I attempt to implement. Unfortunatly I do not have endian.h where it is supposed to reside on my mingw compiler. Is this a linux only include?
Jesse Coyle

#14 Francois Hamel

    Valued Member

  • Members
  • PipPip
  • 86 posts

Posted 17 September 2004 - 11:10 PM

Here's what you can do:

  unsigned char myFakeWORD[2] = { 0xFF, 0x00 };
  unsigned short myRealWORD = *((unsigned short*)myFakeWORD);
  if(myRealWORD == 0xFF00)
  {
    printf("we are in BIG ENDIAN baby!");
  }
  else
  {
    printf("oh crap...not LITTLE ENDIAN! Who invented this shit!?");
  }

I post with style, do you?

http://fhamel.blogspot.com/

#15 Francois Hamel

    Valued Member

  • Members
  • PipPip
  • 86 posts

Posted 17 September 2004 - 11:15 PM

damn I think I should pay more attention before posting...
sorry for stating the already stated :)
I post with style, do you?

http://fhamel.blogspot.com/

#16 Michael

    Member

  • Members
  • PipPip
  • 67 posts

Posted 18 September 2004 - 04:28 AM

You could include one of the WinSock headers.

#17 NomadRock

    Senior Member

  • Members
  • PipPipPipPip
  • 785 posts

Posted 18 September 2004 - 07:08 AM

The whole idea is for this to work outside of windows x86 systems as well as on those systems.

I was writing an app in C that could be compiled on windows, linux, or solaris.
Jesse Coyle

#18 Michael

    Member

  • Members
  • PipPip
  • 67 posts

Posted 18 September 2004 - 01:44 PM

htonl etc are available on basically every platform that has a BSD-style socket interface.

#19 NomadRock

    Senior Member

  • Members
  • PipPipPipPip
  • 785 posts

Posted 18 September 2004 - 05:00 PM

I wanted to try and avoid a page of #if / #includes to find the right headers on any system
Jesse Coyle

#20 Michael

    Member

  • Members
  • PipPip
  • 67 posts

Posted 18 September 2004 - 05:15 PM

If you would restrict your set of a platforms to the relevant (quasi)standard, and the relevant (quasi)standard would enforce the existance of certain header files, that was possible. <wink>





1 user(s) are reading this topic

0 members, 1 guests, 0 anonymous users