Копирование младших байтов целого числа с сохранением порядка байтов - PullRequest
0 голосов
/ 22 декабря 2018

Мне нужно написать функцию, которая копирует указанное количество младших байтов данного целого числа в адрес в памяти, сохраняя при этом их порядок.

void lo_bytes(uint8_t *dest, uint8_t no_bytes, uint32_t val)

Я ожидаю, что использование будет выглядеть следующим образомthis:

uint8 dest[3];
lo_bytes(dest, 3, 0x44332211);
// Big-endian:    dest = 33 22 11
// Little-endian: dest = 11 22 33

Я пытался реализовать функцию, используя сдвиги битов, memcpy, и повторяя каждый байт val с циклом for, но все мои попытки не увенчались успехомработать с одним или другим порядком байтов.

Возможно ли сделать это независимым от платформы способом, или мне нужно использовать #ifdef s и иметь отдельный кусок кода для каждого порядка байтов?

Ответы [ 3 ]

0 голосов
/ 22 декабря 2018

Я пытался реализовать функцию, используя сдвиги битов, memcpy и повторяя каждый байт val с циклом for, но все мои попытки не сработали ни на одном, нидругой порядок байтов.

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

Вы можете работать с представлениями объектов с помощью различных подходов, но вам все равно нужно знатькакие байты оперируют.Это требует некоторой формы обнаружения.Если big-endian и little-endian являются единственными байтовыми порядками, которые вы хотите поддерживать, то я предпочитаю подход, аналогичный описанному в ответе @P__J __:

void lo_bytes(uint8_t *dest, uint8_t no_bytes, uint32_t val) {
    static const union { uint32_t i; uint8_t a[4] } ubytes = { 1 };

    memcpy(dest, &val + (1 - ubytes.a[0]) * (4 - no_bytes), no_bytes);
}

Выражение (1 - ubytes.a[0]) оценивается как1, если представление uint32_t является байтом с прямым порядком байтов, и в этом случае старшие байты появляются в начале представления val.В этом случае мы хотим пропустить первый 4 - no_bytes представления и скопировать остальные.Если uint32_t имеет представление с прямым порядком байтов, с другой стороны, (1 - ubytes.a[0]) будет иметь значение 0, в результате чего memcpy начинается в начале представления.В любом случае, какие бы байты ни копировались из представления val, их порядок сохраняется.Вот что memcpy() делает.

0 голосов
/ 22 декабря 2018

Возможно ли сделать это независимым от платформы способом, или мне нужно использовать #ifdefs и иметь отдельный фрагмент кода для каждого порядка байтов?

Нет, чтодаже не имеет смысла.Все, что касается конкретной характеристики платформы (например, порядковый номер), не может быть независимым от платформы.

Пример 1 (независимый от платформы):

// Copy the 3 least significant bytes to dest[]

dest[0] = value & 0xFF; dest[1] = (value >> 8) & 0xFF; dest[2] = (value >> 16) & 0xFF;

Пример 2 (независимый от платформы):

// Copy the 3 most significant bytes to dest[]

dest[0] = (value >> 8) & 0xFF; dest[1] = (value >> 16) & 0xFF; dest[2] = (value >> 24) & 0xFF;

Пример 3 (зависит от платформы):

// I want the least significant bytes on some platforms and the most significant bytes on other platforms

#ifdef PLATFORM_TYPE_A
    dest[0] = value & 0xFF; dest[1] = (value >> 8) & 0xFF; dest[2] = (value >> 16) & 0xFF;
#endif
#ifdef PLATFORM_TYPE_B
    dest[0] = (value >> 8) & 0xFF; dest[1] = (value >> 16) & 0xFF; dest[2] = (value >> 24) & 0xFF;
#endif

Обратите внимание, что нет реальной разницы в том, что является причиной зависимости от платформы (если это порядковый номер или что-то еще), так каккак только у вас есть зависимость от платформы, у вас не может быть независимости от платформы.

0 голосов
/ 22 декабря 2018
int detect_endianess(void)  //1 if little endian 0 if big endianes
{
    union
    {
        uint16_t u16;
        uint8_t u8[2];
    }val = {.u16 = 0x1122};

    return val.u8[0] == 0x22;
}

void lo_bytes(void *dest, uint8_t no_bytes, uint32_t val)
{
    if(detect_endianess())
    {
        memcpy(dest, &val, no_bytes);
    }
    else
    {
        memcpy(dest, (uint8_t *)(&val) + sizeof(val) - no_bytes, no_bytes);
    }
}
...