Endianness conversion of data

7543b5c50738e23b200e69fe697ea85a
0
NomadRock 101 Sep 17, 2004 at 08:26
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.

19 Replies

Please log in or register to post a reply.

99f6aeec9715bb034bba93ba2a7eb360
0
Nick 102 Sep 17, 2004 at 11:09

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

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

6ad5f8c742f1e8ec61000e2b0900fc76
0
davepermen 101 Sep 17, 2004 at 11:23

cool. never noticed this one :D

7543b5c50738e23b200e69fe697ea85a
0
NomadRock 101 Sep 17, 2004 at 13:23

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

40d3c1d8f291e5f90cc05985e00da115
0
Michael 101 Sep 17, 2004 at 13:55

You could also simply use htonl and the likes.

Cc73cff70954c2f7817ba5701fe2dd4b
0
freak0r 101 Sep 17, 2004 at 17:51
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 :)

40d3c1d8f291e5f90cc05985e00da115
0
Michael 101 Sep 17, 2004 at 20:16

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…

7543b5c50738e23b200e69fe697ea85a
0
NomadRock 101 Sep 17, 2004 at 20:46

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.

7543b5c50738e23b200e69fe697ea85a
0
NomadRock 101 Sep 17, 2004 at 20:54

I suppose even better I could use

#define LITTLE_ENDIAN ((0xFF000000 >> 24) & (255))
40d3c1d8f291e5f90cc05985e00da115
0
Michael 101 Sep 17, 2004 at 21:10

@NomadRock

I suppose even better I could use

#define LITTLE_ENDIAN ((0x000000FF << 24) & (0xFF000000))

[snapback]11708[/snapback]

No.

7543b5c50738e23b200e69fe697ea85a
0
NomadRock 101 Sep 17, 2004 at 21:40

Ok, what is wrong with that?

40d3c1d8f291e5f90cc05985e00da115
0
Michael 101 Sep 17, 2004 at 21:42

It doesn’t return 0 for big endian machines.

7543b5c50738e23b200e69fe697ea85a
0
NomadRock 101 Sep 17, 2004 at 22:44

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?

218341be2587d9bdef38af0c2066c308
0
Francois_Hamel 101 Sep 17, 2004 at 23:10

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!?");
  }
218341be2587d9bdef38af0c2066c308
0
Francois_Hamel 101 Sep 17, 2004 at 23:15

damn I think I should pay more attention before posting…
sorry for stating the already stated :)

40d3c1d8f291e5f90cc05985e00da115
0
Michael 101 Sep 18, 2004 at 04:28

You could include one of the WinSock headers.

7543b5c50738e23b200e69fe697ea85a
0
NomadRock 101 Sep 18, 2004 at 07:08

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.

40d3c1d8f291e5f90cc05985e00da115
0
Michael 101 Sep 18, 2004 at 13:44

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

7543b5c50738e23b200e69fe697ea85a
0
NomadRock 101 Sep 18, 2004 at 17:00

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

40d3c1d8f291e5f90cc05985e00da115
0
Michael 101 Sep 18, 2004 at 17:15

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>