2013-09-04 4 views
1

Я пытаюсь прочитать целое число из файла данных, который хранится в формате little endian. Как только я получил соответствующие байты, я изначально вычислил целочисленное значение, добавив числа, умноженные на их вес (арифметический метод ниже), но по какой-то причине значение всегда отклоняется на единицу в наиболее значимом байте.Вычисление целого из его байтов дает странно неправильные результаты

Другие методы, похоже, работают, но я хочу знать, почему результат неверен при использовании следующего кода.

#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); 
} 

Выход:

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

Как вы можете видеть, используя простой сдвиг или умножение дает неправильный ответ. Зачем?

+0

Неявное целочисленное продвижение ... – Mysticial

+0

Неявное продвижение не должно изменять результат в этом случае AFAIK. – NeonMan

+1

Ваши 'char' подписаны и расширяются до 'int', а не с номером. – Mysticial

ответ

3

Я сделал это сто раз. Изменение:

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

Для

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

Или, еще лучше

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

Обратите внимание, что char может быть больше, чем 8 бит (я работал в системе с 32-битный размер полукокса)

+0

Вы бы подумали, если бы вы сделали это сто раз, вы бы уже знали :-) +1. – paxdiablo

+0

lol. Иногда мне кажется, что я просто не узнаю ;-). – ash

+1

Вот и все. uint8_t. – NeonMan

0

Для дальнейшего изучения этой проблемы попробуйте использовать значения:

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