Перейти к основному содержимому

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

Инженеру

Endianness (порядок байтов) — правило, в каком порядке байты многобайтового числа записываются в память. Для одного и того же значения 0x00000006 (число 6 в 32‑битном слове) байты могут идти "от старшего" или "от младшего" — и это не видно при работе на одной машине, но ломает обмен бинарными данными между x86 и некоторыми сетевыми протоколами.

Термины big-endian и little-endian ввёл Danny Cohen (1980), отсылая к спору из "Путешествий Гулливера" Свифта — с какого конца разбивать яйцо. Классический пример проблемы — обмен структурой "строка + два int" между машинами с разным порядком байт.


Байт, слово, адрес

ТерминСмысл
Байт8 бит; минимальная адресуемая ячейка в большинстве современных CPU
СловоНесколько байт, с которыми работает команда (32 или 64 бита)
АдресНомер ячейки памяти; у слова один базовый адрес, внутри — несколько байт

32‑битное слово по адресу 0 занимает байты 0…3, 64‑битное — 0…7. Вопрос endianness — какой байт считается "первым" внутри слова.


Big-endian и little-endian

РежимПорядок байтов в словеТипичные платформы
Big-endianСтарший байт по младшему адресу (слева направо в диаграммах)Старые SPARC, часть мэйнфреймов IBM, сетевые протоколы
Little-endianМладший байт по младшему адресуx86/x86-64, большинство ARM в режиме по умолчанию

Пример: 32‑битное число 6 (…00000110 в младших битах).

Адрес байта0123
Little-endian (Intel)06000000
Big-endian (SPARC)00000006

Число одно и то же для CPU своей архитектуры. Проблема начинается при копировании сырых байт на другую машину или при чтении файла, записанного на другой endianness.


Смешанные записи — строка и числа

Запись "Jim Smith, 21 год, отдел 260" в памяти часто выглядит так: строка (байты символов + нулевой терминатор до границы слова) + два int (возраст, номер отдела).

При передаче побайтно по сети без преобразования:

  • Строка может отображаться зеркально (MIJ…), если порядок байт внутри слова "перепутался" относительно ожиданий;
  • Целые числа умножаются на степени 256 — возраст 21 превращается в гигантское значение.

Универсального "просто перевернуть слово" нет: для строки нужен порядок символов, для int — иногда инверсия байт внутри слова. Поэтому в протоколах задают явный формат (JSON, Protobuf, TLV) или фиксированный network byte order.


Network byte order

В IP и многих бинарных протоколах multi-byte поля передают в big-endian (старший байт первым). В C для этого есть функции htons, htonl, ntohs, ntohl — host to network / network to host.

СитуацияПрактика
API по HTTP/JSONEndianness не важен — текст и числа в десятичном виде
Сокеты, бинарные заголовкиЯвное преобразование или стандарт big-endian
Файлы struct через fwriteНе переносимы между архитектурами без соглашения
WASM, Java .classФиксированный порядок байт в формате файла

Подробнее про переносимость бинарных структур в C — в языке C.


Как проверить на своей машине

#include <stdio.h>

int main(void) {
unsigned int x = 0x04030201;
unsigned char *p = (unsigned char *)&x;
if (p[0] == 0x01)
puts("little-endian");
else if (p[0] == 0x04)
puts("big-endian");
return 0;
}

На типичном ПК с Windows или Linux на x86-64 вывод будет little-endian.


Связь с архитектурой

Endianness — свойство ISA и реализации, а не "Windows vs Linux". Linux на ARM может быть little-endian; некоторые встраиваемые ядра — big-endian. При сравнении x86, ARM и RISC-V endianness входит в чек-лист переноса прошивки и протоколов.

Практическое правило

Текстовые форматы и JSON решают 99% задач без думания об endianness. Бинарные форматы и общая память между устройствами — всегда явная спецификация порядка байт.


Рекомендую читать дальше