Порядок байтов (endianness) — это соглашение о том, в какой последовательности байты многобайтового числа лежат в памяти или передаются по сети. Есть два основных варианта: big-endian (старший байт первым) и little-endian (младший байт первым). От выбора зависит, как одно и то же число выглядит в дампе памяти и как его читать на другой машине.
Содержание
Ниже разберу главное: чем big-endian отличается от little-endian, где какой порядок принят (сеть — big-endian, процессоры x86 — little-endian), как определить порядок прямо в коде и зачем нужны функции htons/ntohl. Весь код я прогнал и сверил вывод с текстом.
Бит, байт и откуда берется порядок байтов
Начнем с единиц. Бит (binary digit) — минимальная единица информации, принимает значение 0 или 1. Байт — группа из 8 битов, поэтому один байт хранит числа от 0 до 255.
Пока число помещается в один байт, никакого порядка байтов нет: байт один, спорить не о чем. Порядок появляется, когда число занимает несколько байтов — например, 4-байтовое целое uint32_t.
Возьмем число 0x12345678 (шестнадцатеричная запись, каждые две цифры — один байт). В нем четыре байта: 12, 34, 56, 78. Байт 12 — самый старший (most significant byte, MSB), байт 78 — самый младший (least significant byte, LSB). Вопрос порядка байтов — какой из них записать в память первым.
Big-endian и little-endian: в чем разница
Различие только в том, с какого байта — старшего или младшего — начинается запись.
Big-endian (прямой порядок) — первым идет старший байт (MSB). Число 0x12345678 ложится в память как 12 34 56 78, то есть как мы привыкли писать числа слева направо.
Little-endian (обратный порядок) — первым идет младший байт (LSB). То же число ложится как 78 56 34 12 — «задом наперед» относительно привычной записи.
| Признак | Big-endian | Little-endian |
|---|---|---|
| Первый байт в памяти | старший (MSB) | младший (LSB) |
0x12345678 в памяти |
12 34 56 78 |
78 56 34 12 |
| Другое название | network byte order, Motorola | Intel byte order |
| Читается человеком | как обычная запись числа | в обратном порядке |
Названия пришли из «Путешествий Гулливера»: там спорили, с какого конца разбивать яйцо — с тупого (big end) или острого (little end). В 1980 году Дэнни Коэн перенес эту метафору на спор о порядке байтов в статье «On Holy Wars and a Plea for Peace».
У little-endian есть практическое удобство: младший байт всегда лежит по младшему адресу. Поэтому при чтении числа как более короткого типа (например, взять младший байт от int) адрес не меняется — берем первый байт, и это работает независимо от того, 2-, 4- или 8-байтовое число.
Где какой порядок встречается
Однозначно «правильного» порядка нет — это соглашение. Но по областям он распределен вполне устойчиво.
| Контекст | Порядок |
|---|---|
| Сеть (TCP/IP, заголовки пакетов) | big-endian (network byte order) |
| Процессоры x86 и x86-64 (Intel, AMD) | little-endian |
| ARM (Android, iOS, большинство Linux) | обычно little-endian |
| Классические SPARC, Motorola 68000, IBM z | big-endian |
| Формат PNG | big-endian |
| Форматы BMP, USB, GUID-заголовок GPT | little-endian |
Ключевое противоречие для разработчика: сеть работает в big-endian, а массовые процессоры x86 — в little-endian. Значит, при отправке многобайтовых чисел по сети их порядок приходится преобразовывать, иначе принимающая сторона прочитает мусор.
ARM формально bi-endian — порядок можно переключать, — но на практике в Android, iOS и типичных Linux-сборках используется little-endian. Существовал и исторический «смешанный» порядок (middle-endian) в PDP-11, сегодня это экзотика.
Как проверить порядок байтов в коде
Проще всего посмотреть, как число реально разложилось по байтам. В Python это делает метод int.to_bytes, где порядок задается явно:
import sys
n = 0x12345678
print("порядок этой машины:", sys.byteorder)
print("big-endian: ", n.to_bytes(4, "big").hex(" "))
print("little-endian:", n.to_bytes(4, "little").hex(" "))
Вывод (на процессоре x86/ARM):
порядок этой машины: little
big-endian: 12 34 56 78
little-endian: 78 56 34 12
sys.byteorder возвращает порядок текущей машины ('little' на x86 и типичном ARM). Метод to_bytes(4, "big") раскладывает число в 4 байта в прямом порядке, to_bytes(4, "little") — в обратном. Обратное преобразование — int.from_bytes(data, "big").
В C порядок машины определяют «на живом числе»: кладут в память двухбайтовое число 1 и смотрят, что лежит в первом байте:
#include <stdio.h>
#include <stdint.h>
int main(void) {
uint32_t x = 0x12345678;
unsigned char *p = (unsigned char *)&x;
printf("байты в памяти: %02x %02x %02x %02x\n", p[0], p[1], p[2], p[3]);
uint16_t one = 1;
if (*(unsigned char *)&one == 1)
printf("порядок: little-endian\n");
else
printf("порядок: big-endian\n");
return 0;
}
Вывод (на x86/ARM):
байты в памяти: 78 56 34 12
порядок: little-endian
Указатель p смотрит на первый байт числа x. Если первым лежит младший байт (78), машина little-endian. Трюк с uint16_t one = 1: у числа 1 единица — в младшем байте, поэтому первый байт равен 1 только на little-endian.
htons, htonl, ntohs, ntohl: перевод для сети
Чтобы не писать проверку порядка вручную в каждом сетевом приложении, в C есть стандартные функции из <arpa/inet.h>. Они переводят числа между порядком хоста (host) и порядком сети (network, всегда big-endian):
htons— host to network short (16 бит);htonl— host to network long (32 бита);ntohs,ntohl— обратно, из сетевого порядка в порядок хоста.
#include <stdio.h>
#include <stdint.h>
#include <arpa/inet.h>
int main(void) {
uint16_t port = 0x1234;
uint32_t addr = 0x12345678;
printf("htons(0x1234) = 0x%04x\n", htons(port));
printf("htonl(0x12345678) = 0x%08x\n", htonl(addr));
printf("ntohs(0x3412) = 0x%04x\n", ntohs(0x3412));
return 0;
}
Вывод (на x86/ARM, little-endian):
htons(0x1234) = 0x3412
htonl(0x12345678) = 0x78563412
ntohs(0x3412) = 0x1234
Здесь виден смысл функций: на little-endian хосте htons переставляет байты (0x1234 становится 0x3412), приводя число к сетевому big-endian. На big-endian хосте те же функции ничего не меняют — число уже в нужном порядке. Именно поэтому код с htons/htonl переносим: он делает правильное преобразование независимо от архитектуры, и его нужно применять к номерам портов и адресам перед отправкой, а ntohs/ntohl — к принятым данным.
FAQ
Как быстро запомнить, что есть что? Big-endian — «большой конец первым»: старший (самый весомый) байт идет в начало, как в обычной записи числа. Little-endian — «маленький конец первым»: первым лежит младший байт.
Влияет ли порядок байтов на строки и отдельные байты? Нет. Порядок байтов касается только многобайтовых чисел. Массив байтов, строка в однобайтовой кодировке или отдельный char лежат одинаково при любом порядке — переставлять там нечего.
Что такое bi-endian процессор? Это процессор (например, ARM, PowerPC), у которого порядок байтов можно переключить настройкой. На практике конкретная операционная система фиксирует один режим — для ARM в мобильных и десктопных системах это обычно little-endian.
Выводы
- Порядок байтов (endianness) — соглашение о последовательности байтов многобайтового числа; для одного байта его не существует.
- Big-endian: первым идет старший байт (
0x12345678->12 34 56 78); little-endian: первым младший (78 56 34 12). - Сеть (TCP/IP) — big-endian (network byte order), процессоры x86/x86-64 и обычно ARM — little-endian; отсюда необходимость преобразований при передаче по сети.
- Проверить порядок машины: в Python —
sys.byteorderиint.to_bytes; в C — через указатель на первый байт числа. - Для сети применяйте
htons/htonlк исходящим числам иntohs/ntohlк входящим — код останется переносимым между архитектурами.
Где это пригодится на практике
Порядок байтов всплывает в сетевом программировании, при разборе бинарных форматов файлов, чтении данных с датчиков и микроконтроллеров, отладке дампов памяти и межплатформенной сериализации. Ошибка с порядком дает не падение, а тихо «перевернутое» число — такие баги ловить сложнее всего, поэтому понимать endianness полезно любому системному разработчику.
Освойте тему на практике
Разобрать работу с памятью, бинарными данными и низкоуровневыми деталями на практике помогает курс Системное программирование: на нем разбирают представление данных, работу с C и взаимодействие с операционной системой.
Освойте тему на практике
Посмотреть, как преподаватели объясняют такие темы, и задать свои вопросы можно на открытых уроках Otus — они бесплатные и проходят регулярно.
Смежные темы: Все о системах счисления в информатике, Сокет: определение и особенности, Протоколы данных: описание и разновидности.



