efg's Computer Lab Tips and Tricks

Big Endian and Little Endian

Subject: Re: Help with fields alignment in record in Delphi 3
From: "Earl F. Glynn" 
Date: 1997/11/07
Newsgroups: alt.comp.lang.borland-delphi
You have just discovered the problem with "Little Endian" alignment of bytes within words (or integers) on Intel machines. (Other computers, e.g., Sun and IBM mainframes are "Big Endian" machines.)

When you have the logical numeric value $1234 (decimal 4660), this number is NOT stored in this order in memory. It is stored as $3412. The "little end" of the number is at the beginning so this is called "little endian". Your "1" constants above are flipped just like this.

A 4-byte integer is even more interesting:

$12345678 (logical order)

56781234 swap high and low 2-byte words (intermediate step for recursive algorithm)

78563412 swap bytes within 2-byte words <- this is how it's stored!
with the "little end" first.

This whole problem is a great example of how someone tried to optimize something (in this case in hardware) and introduced
great unnecessary complexity to other problems. But it's something we have to live with.

Subject: Re: IEEE standard single-precision format to Delphi 3 format
From: "Earl F. Glynn" 
Date: 1997/12/31
Newsgroups: borland.public.delphi.objectpascal
Here's some code that should get you started using a variant
record to look at the four individual bytes within a single value
(you also could use pointers to do the same thing):

procedure TForm1.Button1Click(Sender: TObject);

    SingleOverlay =
    RECORD // cases in variant overlay same memory area
        1: (float: Single);
        2: (b: ARRAY[1..4] OF BYTE);
    END; // only one END here!

    z: SingleOverlay;
    a: SingleOverlay;
  z.float := 1.305085E3;

  // Emphasize little endian order
  // Result is "B822A344" that in "normal" order
  // would be 44A322B8.
  label1.caption :=
    [z.b[1], z.b[2], z.b[3], z.b[4]]);

  // $44A322C0 in "little endian" is
  // $C022A344 gives value of 1305.0859375
  a.b[1] := $C0;
  a.b[2] := $22;
  a.b[3] := $A3;
  a.b[4] := $44;
  label2.caption := FloatToStr(a.float);


Subject: Re: Converting floating point data from SUN to PC - ? how
From: "Earl F. Glynn" 
Date: 1997/02/13
Newsgroups: comp.lang.pascal.delphi.misc
With 8-byte doubles in C on a "big endian" Sun workstation, the logical arrangement of hex digits is in a "normal" order. On a PC, with "little endian" order, just swap 4-byte "words", swap 2-byte "words" within 4-byte "words", swap bytes within 2-byte "words". This can be done recursively. Unfortunately, I only could find C code that shows this:

void swap(BYTE *x, BYTE size)
  unsigned char c;
  unsigned short s;
  unsigned long l;

  switch (size)
    case 2: /* swap two bytes */
      c = *x;
      *x = *(x+1);
      *(x+1) = c;
    case 4: /* swap two shorts (2-byte words) */
      s = *(unsigned short *)x;
      *(unsigned short *)x = *((unsigned short *)x + 1);
      *((unsigned short *)x + 1) = s;
      swap ((char *)x, 2);
      swap ((char *)((unsigned short *)x+1), 2);
    case 8: /* swap two longs (4-bytes words) */
      l = *(unsigned long *)x;
      *(unsigned long *)x = *((unsigned long *)x + 1);
      *((unsigned long *)x + 1) = l;
      swap ((char *)x, 4);
      swap ((char *)((unsigned long *)x+1), 4);


For 2-bytes "words": x'1234' on Sun becomes x'3412' on PCs.

For 4-byte "words" (integers or single floats):
x'12345678' on Sun becomes x'78563412' on PCs.

Steps: 1234 5678
5678 1234
7856 3412

For 8-byte "words" (doubles):
x'0123456789abcdef' becomes x'efcdab8967452301'

Here are the steps:
1. x'0123456789abcdef' -> 01234567 89abcdef

2. swap 4-byte words: 89abcdef 01234567

3. swap 2-byte words in
each 4-byte word: cdef89ab 45670123

4. swap bytes within each
2-byte word: efcdab89 67452301

Follow this procedure going in either direction, Sun to
PC or PC to Sun. I used to just compile a constant
in the code and write one in the data stream. Whenever
they were different, I applied the swapping above.


Updated 27 Nov 2002