applications, ideas, technology, solutions

The End of Endianness

I very much dislike dealing with cross-platform endian issues.   When it comes to defining structures with bitfields–it can sometimes become a pain to order all the fields correctly depending on the platform one is using.

Another headache is dealing with host byte ordering and network traffic on Intel platforms–all that byte swapping!!!

Anyway, I’ve been using some simple functions that allow me to parse the message on the fly while it is still in network byte order with no need for byte swapping or structures with bitfields.

The great thing about this code is that it is cross-platform; absolutely no endian issues to deal with.  The price paid for this portability is execution speed–this code will likely be slower when parsing many fields out of a large message.  But if you only need one or two fields from a large message, then this code will actually be faster than byte swapping the entire message.

Below you will find the bitfield extract code header file, then give a small sample program which uses it, and its corresponding output.

Here’s the bitfieldextract.h header file:

#ifndef __BITFIELDEXTRACT_H__
#define __BITFIELDEXTRACT_H__

#if !defined(WIN32)
typedef unsigned long UINT32;
typedef unsigned short UINT16;
typedef unsigned char UCHAR;
typedef unsigned char *PUCHAR;
typedef char *PCHAR;
#else
#include 
#endif

/*
//
// bfx -- bit field extract
//
// extract up to a 32-bit value at any bit
// offset in a byte array
//
*/
inline UINT32 bfx(
  const PUCHAR cptr,
  UINT32 bit_offset,
  UINT32 bit_len)
{
  /*
  // Portable bit field extract code
  */

  UINT32 byte_off    = ( bit_offset >> 3 );
  UINT32 left_shift  = bit_offset - ( byte_off << 3 );
  UINT32 bytes       = ( left_shift + bit_len + 7 ) >> 3;
  UINT32 right_shift = ( bytes << 3 ) - ( bit_len + left_shift );
  UINT8  cval;
  UINT32 val, i;

  /* grab first byte  and apply shift */
  cval = cptr[byte_off] << left_shift;
  val  = cval;
  bytes -= 1;

  if (bytes) {
    /* shift back high order byte */
    val >>= left_shift;

    /* reset left shift since we did it already */
    left_shift = 0;
  }

  for (i=1;i> right_shift );

    /* reset right shift since we did it already */
    right_shift = 0;
  }

  return val >> ( left_shift + right_shift );
}

/*
// bfxi -- bit field extract and increment
//
// extract up to a 32-bit value at any bit
// offset in a byte array and auto-increment
// the bit offset by the number of bits read
*/
inline UINT32 bfxi(
  const PUCHAR cptr,
  UINT32 &bit_offset,
  UINT32 bit_len)
{
  UINT32 val = bfx(cptr, bit_offset, bit_len);

  bit_offset += bit_len;

  return val;
}

#endif

Here’s a small program that uses it:

#include 
#include "bitfieldextract.h"

using namespace std;

int main(int argc, char* argv[])
{
  UCHAR x[6] = { 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc };
  unsigned int ofs = 0;
  int i;

  cout << "Binary representation of buffer "
    << "[ 0x12 0x34 0x56 0x78 0x9a 0xbc ]:"
    << endl << endl << "  ";

  for (i=0;i<48;i++)
    cout << bfxi(x, ofs, 1);
  cout << endl << endl; 

  cout << "Each 4-bit nibble:"
    << endl << endl << "  ";

  ofs = 0;
  for (i=0;i<12;i++)
    printf("0x%1x ", bfxi(x, ofs, 4));
  cout << endl << endl; 

  ofs = 2;
  cout << " 2 bits at " << ofs << " = ";
  cout << bfxi( x, ofs, 2 ) << endl;
  cout << " 4 bits at " << ofs << " = ";
  cout << bfxi( x, ofs, 4 ) << endl;
  cout << " 6 bits at " << ofs << " = ";
  cout << bfxi( x, ofs, 6 ) << endl;
  cout << " 8 bits at " << ofs << " = ";
  cout << bfxi( x, ofs, 8 ) << endl;
  cout << "10 bits at " << ofs << " = ";
  cout << bfxi( x, ofs, 10) << endl;

  for (i=4;i<=8;i++) {
    ofs = i;
    cout << "32 bits at " << ofs << " = ";
    printf("0x%08x\n", bfxi( x, ofs, 32));
  }
  ofs = 16;
  cout << "32 bits at " << ofs << " = "; 
  printf("0x%08x\n", bfxi( x, ofs, 32));

  return 0;

}

And the associated output:

Binary representation of buffer [ 0x12 0x34 0x56 0x78 0x9a 0xbc ]:

  000100100011010001010110011110001001101010111100

Each 4-bit nibble:

  0x1 0x2 0x3 0x4 0x5 0x6 0x7 0x8 0x9 0xa 0xb 0xc

 2 bits at 2 = 1
 4 bits at 4 = 2
 6 bits at 8 = 13
 8 bits at 14 = 21
10 bits at 22 = 632
32 bits at 4 = 0x23456789
32 bits at 5 = 0x468acf13
32 bits at 6 = 0x8d159e26
32 bits at 7 = 0x1a2b3c4d
32 bits at 8 = 0x3456789a
32 bits at 16 = 0x56789abc

No Comments Yet

Leave a Reply

Your email address will not be published. Required fields are marked *


*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>