Calculating an integer from its Bytes gives oddly wrong results

122 views Asked by At

I'm trying to read an integer from a data file which is stored raw in little endian format. Once I got the corresponding bytes I originally calculated the integer value by adding the numbers multiplied by their weight (aritmetic method below) but for some reason the value is allways off by one unit on the most significant byte.

Other methods seem to work but I want to know why the result is wrong when using the following code.

#include <stdio.h>
#include <stdint.h>

void main(){
  //Two bytes that form a 16-bit integer (Little endian)
  char b[2] = {0xBD, 0x74};

  //This gives a correct answer (Shift + Extra masking)
  uint16_t n_correct;
  n_correct = (b[0] & 0xFF) + ((b[1]<<8) & 0xFF00);
  //This should give a correct answer but doesn't (Shifting method)
  uint16_t n_incorrect;
  n_incorrect = b[0] + (b[1]<<8);
  //This should also give a correct answer but doesn't (Aritmetic)
  uint16_t n_arith;
  n_arith = b[0] + (b[1]*256);
  //This works, on little endian machines. Dirty but works. (Hack)
  uint16_t n_hack;
  uint8_t* n_ptr = (uint8_t*)&n_hack;
  n_ptr[0] = b[0];
  n_ptr[1] = b[1];

  printf("Shifting method: %X == %X%X?\n", n_incorrect, b[1]&0xFF, b[0]&0xFF);
  printf("Shift + Masking: %X == %X%X?\n", n_correct, b[1]&0xFF, b[0]&0xFF);
  printf("     Arithmetic: %X == %X%X?\n", n_arith, b[1]&0xFF, b[0]&0xFF);
  printf("           Hack: %X == %X%X?\n", n_hack, b[1]&0xFF, b[0]&0xFF);
}

The output is:

Shifting method: 73BD == 74BD?
Shift + Masking: 74BD == 74BD?
     Arithmetic: 73BD == 74BD?
           Hack: 74BD == 74BD?

As you can see, using plain shifting or multiplication gives the wrong answer. why?

2

There are 2 answers

1
ash On BEST ANSWER

I've done this a hundred times. Change:

char b[2] = {0xBD, 0x74};

To

unsigned char b[2] = {0xBD, 0x74};

Or, better yet

uint8_t b[2] = {0xBD, 0x74};

Note that char can be more than 8 bits (I worked on a system with a 32-bit char size)

0
JackCColeman On

To further explore this problem, try values of:

 char b[2] = {0xBD, 0x01};
 char b[2] = {0xBD, 0x00};