Embedded Questions and Answers

Related To All the Questions:

Memory Related Explanations:

Basic concepts on Endianness

  • Big-Endian means that the most significant byte of any multibyte data field is stored at the lowest memory address, which is also the address of the larger field.
  • Little-Endian means that the least significant byte of any multibyte data field is stored at the lowest memory address, which is also the address of the larger field.

How to switch from one format to the other?

It is very easy to reverse a multi-byte number if you need the other format, it is simply a matter of swapping bytes and the conversion is the same in both directions. The following example shows how an Endian conversion function could be implemented using simple C unions:

unsigned long ByteSwap1 (unsigned long nLongNumber)

{

   union u {unsigned long vi; unsigned char c[sizeof(unsigned long)];};

   union v {unsigned long ni; unsigned char d[sizeof(unsigned long)];};

   union u un;

   union v vn;

   un.vi = nLongNumber;

   vn.d[0]=un.c[3];

   vn.d[1]=un.c[2];

   vn.d[2]=un.c[1];

   vn.d[3]=un.c[0];

   return (vn.ni);

}

Note that this function is intented to work with 32-bit integers.

A more efficient function can be implemented using bitwise operations as shown below:

unsigned long ByteSwap2 (unsigned long nLongNumber)

{

   return(((nLongNumber&0x000000FF)<<24)+((nLongNumber&0x0000FF00)<<8)+((nLongNumber&0x00FF0000)>>8)+((nLongNumber&0xFF000000)>>24));

}

A 16-bit version of a byte swap function is really straightforward:

unsigned short ByteSwap4 (unsigned short nValue)

{

   return (((nValue>> 8)) | (nValue << 8));

}

Finally, we can write a more general function that can deal with any atomic data type (e.g. int, float, double, etc) with automatic size detection:

#include <algorithm> //required for std::swap

#define ByteSwap5(x) ByteSwap((unsigned char *) &x,sizeof(x))

void ByteSwap(unsigned char * b, int n)

{

   register int i = 0;

   register int j = n-1;

   while (i<j)

   {

      std::swap(b[i], b[j]);

      i++, j–;

   }

}

For example, the next code snippet shows how to convert a data array of doubles from one format (e.g. Big-Endian) to the other (e.g. Little-Endian):

double* dArray; //array in big-endian format

int n; //Number of elements

for (register int i = 0; i <n; i++)

   ByteSwap5(dArray[i]);

Who to know whether system uses big endian or little endian format and how to convert among them?

Here is a small code segment to determine the endianess of a system at run time.
1)      short int number = 0x1;
          char *byte = (char*)&number;
          if ( byte[0] )
                    printf(“Little endian”);
          else
                    printf(“Big endian”);
                                     
OR
2)      unsigned int a = 0x01;
a = a>>1;
if(a){
          printf(“little endian”);
}

else{
          printf(“big endian”);
}

How to dynamically test for the Endian type at run time?

You can use the following function to see if your code is running on a Little- or Big-Endian system:

#define BIG_ENDIAN      0

#define LITTLE_ENDIAN   1

int TestByteOrder()

{

   short int word = 0x0001;

   char *byte = (char *) &word;

   return(byte[0] ? LITTLE_ENDIAN : BIG_ENDIAN);

}

This code assigns the value 0001h to a 16-bit integer. A char pointer is then assigned to point at the first (least-significant) byte of the integer value. If the first byte of the integer is 0x01h, then the system is Little-Endian (the 0x01h is in the lowest, or least-significant, address). If it is 0x00h then the system is Big-Endian.

Similarly,

bool IsBigEndian()

{

   short word = 0x4321;

   if((*(char *)& word) != 0x21 )

     return true;

   else

     return false;

}

which is just the reverse of the same coin.

You can also use the standard byte order API�s to determine the byte-order of a system at run-time. For example:

bool IsBigEndian() { return( htonl(1)==1 ); }

Advertisements