взять uint16_t из массива uint8_t дать неверный результат? - PullRequest
0 голосов
/ 21 марта 2019

У меня есть массив байтов:

uint8_t* data = 10101010 01000001 00000000 00010010 00000000 00000010..........



uint8_t get_U8(uint8_t * data, int* offset)
{
    uint8_t tmp = *((uint8_t*)(data + *offset));
    *offset += sizeof(uint8_t);
    return tmp;
}

uint16_t get_U16(uint8_t* data, int* offset)
{
    uint16_t tmp = *((uint16_t*)(data + *offset));
    *offset += sizeof(uint16_t);
    return tmp;
}

смещение здесь равно 2.

get_U8(data, 0) = 10101010 = 170  ===> OK

get_U8(data, 1) = 01000001 = 65   ===> OK

get_U8(data, 2) = 00000000 = 0    ===> OK

get_U8(data, 3) = 00010010 = 18   ===> OK

, но

get_U16(data, 2) = 4608    ===> NOT OK (should be 18)

4608 = 00010010 00000000 

Так что я понимаю, что 2 байтаинвертированы.

Я не понимаю, почему get_U16 инвертирует позицию байтов, и это не проблема с прямым порядком байтов / байтов, потому что здесь это первые 8 бит, инвертированные с 8-секундными битами.

Я просто ожидаю, что uint16_t просто возьмет 16 бит в заданной позиции и вернет здесь 18.

Может кто-нибудь сказать мне, что я делаю неправильно?

Ответы [ 2 ]

3 голосов
/ 21 марта 2019

Я не понимаю, почему get_U16 инвертирует позицию байтов, и это не проблема с прямым или прямым порядком байтов, потому что здесь это первые 8 бит, инвертированные с 8 секундными битами.

Это неверно.Endianess касается порядка байтов в больших типах данных.В этом случае младший байт, кажется, хранится по самому низкому адресу.

Когда вы читаете адрес (назовите его p) индекса 2 для uint16_t, память по этому адресусодержит младший байт значения.Адрес p + 1 содержит старший байт значения.

2 голосов
/ 21 марта 2019

Вы должны все обработать вручную.

uint8_t get_U8(uint8_t * data, int* offset)
{
    uint8_t tmp;
    # I think the following should work even on systems where `sizeof(uint8_t) != 1`
    memcpy(&tmp, &((unsigned char*)data)[*offset], sizeof(uint8_t));
    *offset += sizeof(uint8_t);
    return tmp;
}

uint16_t get_U16(uint8_t* data, int* offset)
{
    uint8_t tmp1 = get_U8(data, offset);
    uint8_t tmp2 = get_U8(data, offset);
    uint16_t tmp = tmp1 << 16 | tmp2; 
    # or tmp = tmp2 << 16 | tmp1; depending on the endianess you want to have
    return tmp;
}

Выполнение:

uint16_t tmp = *((uint16_t*)(data + *offset));

плохо, очень плохо для буферов, которые вы *offset += меняете вручную. Это может очень легко вызвать неопределенное поведение (читается как: ошибка сегментации), если data + *offset не выровнено uint16_t. Не делай этого. Вы хотите uint16_t из двух байтов? Читайте char за char и используйте сдвиги битов и только сдвиги битов.

это не проблема с прямым или прямым порядком байтов, потому что здесь это первые 8 бит, инвертированные с 8 секундными битами.

Короче говоря: в точности работает как endianess. Он инвертирует первые 8 бит со вторыми 8 битами.

Кто-нибудь может сказать мне, что я делаю неправильно?

Вы не делаете ничего плохого, и ваш код может работать как есть.

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