Переключение порядка байтов без ввода типа

Мне нужно изменить порядок байтов, чтобы int16 с содержимым (byte1, byte2) -> (byte2, byte1). Я сделал это с помощью союза:

union ConversionUnion
{
uint8_t m_8[4];
uint16_t m_16[2];
uint32_t m_32;
};

//use
uint16_t example = 0xFFDE
ConversionUnion converter;
converter.m_16[0] = example;
std::swap(converter.m_8[0], converter.m_8[1]);
example = converter.m_16[0]; //0xDEFF

Теперь это работает на gcc, но мне сообщили, что это неопределенное поведение (gcc 6.3, C ++ 11).

Вопросы:

1) Это действительно неопределенное поведение, я спрашиваю, потому что я видел это раньше во встроенном коде. Другие вопросы о стековом потоке, кажется, обсуждают это, кто на самом деле прав (для C ++ 11 & С ++ 14).

2) Если это неопределенное поведение, можно ли менять порядок следования байтов без переноса множества битов переносимым способом. Я действительно ненавижу немного сдвигаться, это ужасно уродливо.

3

Решение

Тип наказания разрешен через char*так почему бы просто не использовать это, а не союз?

uint16_t example = 0xFFDE;
char *char_alias = reinterpret_cast<char*>(&example);
std::swap(char_alias[0], char_alias[1]);
4

Другие решения

Полагаться на неопределенное поведение или неясную семантику языка (объединения) не обязательно более идиоматично или проще для чтения. Я считаю, что этот цикл гораздо проще разобрать:

uint32_t example = 0xc001c0de;
unsigned char *p = reinterpret_cast<unsigned char*>(&example);

for (size_t low = 0, high = sizeof(example) - 1;
high > low;
++low, --high)
{
std::swap(p[low], p[high]);
}
2

  1. Люди в какой-то степени не согласны с этим. я думаю что

    это неопределенное поведение

    но мое мнение не является ценным дополнением.

  2. Замена байтов проста с неподписанными типами (BTW-замена байтовых типов со знаком не имеет смысла). Просто извлеките отдельные байты и переставьте. Скрыть уродство в constexpr функция или макрос.

    constexpr uint16_t bswap(uint16_t value);
    {
    uint16_t high_byte = (value >> 8) & 0xff;
    uint16_t low_byte = value & 0xff;
    return (low_byte << 8) | high_byte;
    }
    

Кстати, если вы видите что-то во встроенном коде, и это работает, это не означает, что это безопасно! Встроенный код часто жертвует переносимостью ради эффективности, иногда используя неопределенное поведение, когда это был единственный способ убедить конкретный компилятор генерировать эффективный код.

1