9/12/2010

if (Indians || Endians) {...

As part of my research project have been working on some network code in C++. Ran into a couple of issues, which were tracked down to incorrect endian orientation, i.e. big-endian vs. little-endian. While testing a couple of theories, came up with a demo app which may be useful to someone.

#include
#include

#include // printf
#include // atoi

using std::cout;
using std::endl;
using std::string;

/**
 * Declare an integer and check if the high order byte is used or not
 * If the high order byte is used then it's little endian based machine
 * else its using big endian. The function isBigEndian is
 * define as a macro for inline substitution at compile time.
 */
const int ENDIAN = 1;
#define isBigEndian() ((*(char*)&ENDIAN) == 0)

// function prototypes
int reverseInt( int );
void usage();
/**
 * main entry point into the endian demo application. The application accepts
 * an integer from the command-line arguments and displays it as an int, as a
 * hex value and then finally the raw bytes. If the machine is a little-endian
 * based processor then details of the int is also displayed.
 *
 * @param argc - int specifying the number of command line
 *               arguments
 * @param argv - char ** containing the actual command line
 *               arguments
 * @return int - 0 on success, else non-zero value
 */
int main( int argc, char **argv ) {
  // check command line arguments
  if ( argc != 2 ) {
    usage();
    return -1;
  }

  // parse and process command line arguments
  int x = atoi( argv[1] );                  // get the int
  unsigned char *ptr = (unsigned char *)&x; // byte array pointer to int
  int y = 0;                                // variable to hold the reverse int

  // display the int size
  cout << "sizeof(int) = " << sizeof(int) << endl << endl;

  // display info on the int
  printf("dec: %d\n", x);
  printf("hex: 0x%x\n", x);
  printf("bytes: ");
  for (int i=0; i < sizeof(int); i++) {
    printf("0x%x ", ptr[i] ); // using cout is too anoying for formatting!!
  }
  cout << endl;
  string str(( const char * ) ptr );
  cout << "str: " << str << endl;

  // determine endian orientation of machine
  if ( isBigEndian() ) {
    cout << "Big Endian Machine!!!" << endl;
  } else {
    cout << "Little Endian Machine!!!" << endl;
    y = reverseInt(x); // reverse the int
    printf("dec: %d\n", y);
    printf("hex: 0x%x\n", y);
    printf("bytes: ");
    ptr = (unsigned char *)&y;
    for (int i=0; i < sizeof(int); i++) {
      printf("0x%x ", ptr[i] ); // using cout is too anoying for formatting!!
    }
    cout << endl;
    str = (const char *)ptr;
    cout << "str: " << str << endl;
  }

  return 0;
}

/**
 * Should only be called on little endian processers. Reverses the int byte
 * order for little endian machines.
 *
 * @param iNum - int to reverse
 * @param int - the reversed int
 */
int reverseInt( int iNum ) {
  unsigned char *rev = new unsigned char[sizeof(int)];
  for ( int i = 0; i < sizeof(int); i++ ) {
    rev[i] = (iNum >> (8*i)) & 255;
  }

  int ret = 0;
  for ( int i = 0; i < sizeof(int); i++ ) {
    ret += (int)rev[i] << ((sizeof(int) - (i+1)) * 8);
  }

  return ret;
}

/**
 * usage displays the demo program usage information. The usage
 * information is output to stdout.
 */
void usage() {
  cout << "Usage: endian INT" << endl;
  cout << "Endian demo application to check and manipulate int for endian use";
  cout << endl << endl;
  cout << "  INT\t- int value";
  cout << endl << endl;
  cout << "Example:" << endl;
  cout << "  endian 65535" << endl;
}

No comments:

Post a Comment