Перейти к содержанию

Порядок байтов (endianness)

Порядок байтов определяет, каким байтом вперёд многобайтное число хранится в памяти или передаётся по интерфейсу: младшим (little-endian) или старшим (big-endian). Если отправитель и получатель понимают его по-разному, 0x1234 превращается в 0x3412.

Обновлено Редакция GAW

Порядок байтов (endianness, byte order) — правило, по которому многобайтное число раскладывается на байты в памяти или при передаче. При little-endian первым (по младшему адресу) идёт младший байт, при big-endian — старший. Число 0x12345678 в памяти little-endian-процессора лежит байтами 78 56 34 12, а в big-endian — 12 34 56 78. Порядок бит внутри байта при этом обычно не меняется.

Где какой порядок

ГдеПорядокИсточник
AVR (avr-gcc)little-endianGCC Wiki, ABI avr-gcc
STM32 (Cortex-M3/M4)little-endianST PM0056
Modbus: адреса и значения регистровbig-endianспецификация Modbus
Modbus RTU: CRC кадрамладший байт первымMODBUS over Serial Line

Когда микроконтроллер с little-endian отправляет число по протоколу с big-endian, байты нужно переставить. Подробно о порядке байтов в Modbus RTU, включая четыре варианта раскладки float по двум регистрам, — в статье о протоколе.

Типичные ошибки

  • Структура «как есть» в линию. Если отправить структуру из памяти AVR или STM32 копированием байтов, многобайтные поля уйдут младшим байтом вперёд, а приёмник с big-endian прочитает их неверно.
  • 32-битные слова и побайтовые данные. Аппаратный блок CRC STM32 принимает 32-битные слова; если записывать в него поток байтов словами на little-endian-процессоре, порядок байтов внутри слова окажется обратным — подробнее в калькуляторе CRC.
  • Ручная сборка числа из байтов. Надёжнее собирать число сдвигами — (b1 << 8) | b0, — чем приведением указателей: результат не зависит от порядка байтов процессора. Приёмы со сдвигами и масками — в статье о битовых операциях.

Частые вопросы

Какой порядок байтов у AVR и STM32?

Little-endian: младший байт многобайтного числа лежит по младшему адресу. У avr-gcc это зафиксировано в описании ABI, у ядер Cortex-M в STM32 — в руководстве по программированию PM0056. Поэтому 32-битное 0x12345678 в памяти этих микроконтроллеров лежит байтами 78 56 34 12.

Какой порядок байтов в Modbus?

Big-endian: адрес регистра 0x006B передаётся как 00 6B, значение 0x1234 — как 12 34. Единственное исключение — CRC кадра RTU, у неё первым идёт младший байт. А вот 32-битные числа и float в двух регистрах приборы раскладывают по-разному: ABCD, CDAB, BADC или DCBA, и порядок нужно узнавать в документации прибора.

Как поменять порядок байтов в программе?

Сдвигами и масками: ((x >> 8) & 0xFF) | ((x & 0xFF) << 8) для 16 бит. На Cortex-M для этого есть команды REV (байты 32-битного слова) и REV16 (байты в каждом полуслове), а в CMSIS — функции __REV и __REV16, которые компилируются в одну команду.

Источники

  1. Modbus Organization. MODBUS Application Protocol Specification V1.1b3 — разд. 4 — порядок байтов: старший первым (big-endian) для адресов и данных
  2. Modbus Organization. MODBUS over Serial Line Specification and Implementation Guide V1.02 — CRC кадра RTU передаётся младшим байтом вперёд
  3. GCC Wiki: avr-gcc — ABI and implementation defined behaviour — порядок байтов avr-gcc — little-endian
  4. STMicroelectronics. PM0056 Rev 7. STM32F10xxx/20xxx/21xxx/L1xxxx Cortex-M3 programming manual — хранение данных в формате little-endian; команды REV и REV16 — смена порядка байтов

Нашли ошибку?