Порядок байтов — 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 в младших битах).
| Адрес байта | 0 | 1 | 2 | 3 |
|---|---|---|---|---|
| Little-endian (Intel) | 06 | 00 | 00 | 00 |
| Big-endian (SPARC) | 00 | 00 | 00 | 06 |
Число одно и то же для 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/JSON | Endianness не важен — текст и числа в десятичном виде |
| Сокеты, бинарные заголовки | Явное преобразование или стандарт 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. Бинарные форматы и общая память между устройствами — всегда явная спецификация порядка байт.
Рекомендую читать дальше
- RISC и CISC — семейства процессоров
- Многоуровневая организация — уровень ISA
- C — представление данных — union и байты в памяти