Преобразование uint16_t в байты и наоборот — независимо от порядкового номера системы

#c #bitwise-operators #endianness

#c #побитовые операторы #порядковый номер

Вопрос:

Просматривая SO, я обнаружил, что могу сделать следующее, чтобы извлечь байты из a uint16_t , а затем собрать их в исходное число:

 uint16_t x = 700;

// extract the bytes
uint8_t byte1 = (x >> 8) amp; 0xFF;
uint8_t byte2 = x amp; 0xFF;

// reassemble
uint16_t y = (byte1 << 8)   byte2;
  

Но, насколько я понимаю, это будет работать только в системах с малым порядком, а не в системах с большим порядком.

Есть ли способ добиться того же самого независимо от порядкового номера системы?

Комментарии:

1. Нет, это будет работать в любой системе.

2. Порядковый номер не имеет значения. Биты 0..7 16-битного значения всегда являются наименее значимыми. Порядковый номер определяется последовательностью, в которой он хранится в памяти.

3. @KamilCuk «это будет работать в любой системе» -> Возможно. Когда bytes1 >= 128 и int является 16-разрядным, byte1 << 8 это UB . Тем не менее, я никогда не видел 16-разрядную систему, которая не работала бы так, как хотелось. uint16_t y = (1u*byte1 << 8) byte2; является переносимой альтернативой.

Ответ №1:

Ваш код не зависит от порядкового номера. При просмотре битов переменных с использованием масок они всегда будут выглядеть как порядковые. Байты более высокого порядка будут отображаться слева от байтов младшего порядка. Несмотря на то, что на машинах с малым порядковым номером они меняются местами, мы не стали мудрее.

Однако, с учетом сказанного, вы могли бы вместо этого просто скопировать байты, фактически не глядя на них. Никаких масок, никаких сдвигов, просто скопируйте байты:

 // extract the bytes
uint8_t bytes[sizeof(x)];
memcpy(bytes, amp;x, sizeof(x));

// reassemble
uint16_t y;
memcpy(amp;y, bytes, sizeof(y));
  

Комментарии:

1. Промежуточный результат bytes[] _intermediate этого кода зависит от порядкового номера. Надеюсь, это сработает нормально для OP и «… независимо от порядкового номера системы».

2. порядковый номер @chux не имеет значения. Он сохранит и восстановит значение правильно независимо от порядкового номера. Если байты не сохранены и не восстановлены или не переданы между системами с разным порядковым номером. Что также верно для исходного кода OP.

Ответ №2:

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

 Eg. 
Number = 0xAABB

                 Memory Address        Value
Little Endian    0x3000                0xBB
                 0x3001                0xAA

Big Endian       0x3000                0xAA
                 0x3001                0xBB
  

Но при загрузке в 32-разрядный регистр число все равно будет равно 0xAABB, в результате чего uint8_t byte1 и uint8_t byte2 будут иметь одинаковые значения независимо от порядкового номера.