Interested Article - Порядок байтов

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

В общем случае, для представления числа M , большего 255 (здесь 255 = 2 8 1 {\displaystyle 255=2^{8}-1} — максимальное целое число, записываемое одним байтом ), приходится использовать несколько байтов (n). При этом число M записывается в позиционной системе счисления по основанию 256:

M = i = 0 n 1 A i 256 i = A 0 256 0 + A 1 256 1 + A 2 256 2 + + A n 1 256 n 1 . {\displaystyle M=\sum _{i=0}^{n-1}A_{i}\cdot 256^{i}=A_{0}\cdot 256^{0}+A_{1}\cdot 256^{1}+A_{2}\cdot 256^{2}+\dots +A_{n-1}\cdot 256^{n-1}.}

Набор целых чисел A 0 , , A n 1 {\displaystyle A_{0},\dots ,A_{n-1}} , каждое из которых лежит в интервале от 0 до 255, является последовательностью байтов, составляющих M . При этом A 0 {\displaystyle A_{0}} называется младшим байтом , а A n 1 {\displaystyle A_{n-1}} старшим байтом числа M .

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

Варианты записи

Порядок от старшего к младшему

Порядок от старшего к младшему ( англ. big-endian — с большого конца): A n 1 , , A 0 {\displaystyle A_{n-1},\dots ,A_{0}} . Этот порядок подобен привычному порядку записи (например арабскими цифрами ) слева направо , например, число сто двадцать три было бы записано при таком порядке как 123 . В этом же порядке принято записывать байты в технической и учебной литературе, если другой порядок явно не обозначен.

Этот порядок является стандартным для протоколов TCP/IP , он используется в заголовках пакетов данных и во многих протоколах более высокого уровня, разработанных для использования поверх TCP/IP. Поэтому порядок байтов от старшего к младшему часто называют «сетевым порядком байтов» ( англ. network byte order). Этот порядок байтов используется процессорами IBM 360 /370/390, SPARC , Motorola 68000 (отсюда третье название — порядок байтов Motorola , англ. Motorola byte order).

При таком порядке байтов удобно проводить сравнение строк (можно сравнивать их целочисленными полями-частями большей разрядности, каждое из которых содержит несколько символов сразу).

Порядок байтов от старшего к младшему применяется также во многих форматах файлов — например, PNG , FLV , EBML , JPEG .

Порядок от младшего к старшему

Порядок от младшего к старшему ( англ. little-endian — с малого конца): A 0 , , A n 1 {\displaystyle A_{0},\dots ,A_{n-1}}

Это обратный привычному порядку записи чисел арабскими цифрами , например, число сто двадцать три было бы записано при таком порядке как 321 . Иными словами этот порядок подобен правилу записи справа налево.

Этот порядок записи принят в памяти персональных компьютеров с процессорами архитектуры x86 , в связи с чем иногда его называют интеловским порядком байтов (по названию компании-создателя архитектуры x86). Современные процессоры x86 позволяют работать с одно-, двух-, четырёх- и восьмибайтовыми операндами. В таком порядке следования байтов очень удобно то, что при увеличении размера (количества байтов) операнда, значение его первого байта неизменно: 3210 → 3210’0000. При порядке от старшего к младшему значение изменилось бы, например: 0123 → 0000’0123;

Кроме x86, такой порядок байтов применяется в архитектурах VAX (отсюда ещё одно название англ. VAX byte order ), DEC Alpha и многих других.

Также порядок «от младшего к старшему» применяется в USB , PCI , таблице разделов GUID , он рекомендован FidoNet . Но в целом соглашение little-endian поддерживают меньше кросс-платформенных протоколов и форматов данных, чем big-endian .

Переключаемый порядок

Многие процессоры могут работать и в порядке «от младшего к старшему», и в обратном, например, ARM (по умолчанию — little-endian), PowerPC (кроме PowerPC 970 ), DEC Alpha , MIPS , PA-RISC и IA-64 . Обычно порядок байтов выбирается программно во время инициализации операционной системы , но может быть выбран и аппаратно перемычками на материнской плате. В этом случае правильнее говорить о порядке байтов на уровне операционной системы. Переключаемый порядок байтов иногда называют англ. bi-endian .

Смешанный порядок

Смешанный (комбинированный, гибридный) порядок байтов ( англ. middle-endian) иногда используется при работе с числами, длина которых превышает машинное слово . Число представляется последовательностью машинных слов , которые записываются в формате, естественном для данной архитектуры, но сами машинные слова следуют в обратном порядке.

В процессорах VAX и ARM используется смешанное представление для длинных вещественных чисел.

Пример

Далее приведён пример, в котором описывается размещение 4-байтового числа в ОЗУ ЭВМ, доступ к которому может производиться и как к 32-разрядному слову, и побайтно.

Все числа записаны в 16-ричной системе счисления.

Число: 0xA1B2C3D4
Представление A 1 1000000 16 + B 2 10000 16 + C 3 100 16 + D 4 1 16 = A 1 B 2 C 3 D 4 {\displaystyle A1*1000000_{16}+B2*10000_{16}+C3*100_{16}+D4*1_{16}=A1B2C3D4} 161 16 10 6 + 178 16 10 4 + 195 16 10 2 + 212 10 = 2712847316 10 {\displaystyle 161*16_{10}^{6}+178*16_{10}^{4}+195*16_{10}^{2}+212_{10}=2712847316_{10}}
Порядок от младшего к старшему (little-endian) D 4 16 , C 3 16 , B 2 16 , A 1 16 {\displaystyle D4_{16},C3_{16},B2_{16},A1_{16}} 212 10 , 195 10 , 178 10 , 161 10 {\displaystyle 212_{10},195_{10},178_{10},161_{10}}
Порядок от старшего к младшему (big-endian) A 1 16 , B 2 16 , C 3 16 , D 4 16 {\displaystyle A1_{16},B2_{16},C3_{16},D4_{16}} 161 10 , 178 10 , 195 10 , 212 10 {\displaystyle 161_{10},178_{10},195_{10},212_{10}}
Порядок, принятый в PDP-11 (PDP-endian) B 2 16 , A 1 16 , D 4 16 , C 3 16 {\displaystyle B2_{16},A1_{16},D4_{16},C3_{16}} 178 10 , 161 10 , 212 10 , 195 10 {\displaystyle 178_{10},161_{10},212_{10},195_{10}}

Определение порядка байтов

Порядок байтов ( англ. endianness) в конкретной машине можно определить с помощью программы на языке Си (testbyteorder.c):

#include <stdio.h> #include <stdint.h> int main () { uint16_t x = 0x0001; printf("%s-endian\n", *((uint8_t *) &x) ? "little" : "big"); } 

Результаты запуска на big-endian машине ( SPARC ):

 $ uname -m sparc64 $ gcc -o testbyteorder testbyteorder.c $ ./testbyteorder big-endian 

Результаты запуска на little-endian машине ( x86 ):

 $ uname -m i386 $ gcc -o testbyteorder testbyteorder.c $ ./testbyteorder little-endian 

На языке C#:

 if (BitConverter.IsLittleEndian) Console.WriteLine("LittleEndian"); else Console.WriteLine("BigEndian"); 

А на языке Python это сделать ещё проще:

import sys if sys.byteorder == "little": print("Ваш компьютер использует порядок байтов Little Endian") else: print("Ваш компьютер использует порядок байтов Big Endian") 

Вещественные числа

Хранение вещественных чисел также может зависеть от порядка байтов. Так, на x86 используются форматы IEEE 754 со знаком и порядком числа в старших байтах.

Юникод

Если Юникод записан в формате UTF-16 или UTF-32 , то порядок байтов уже существенен. Одним из способов обозначения порядка байтов в юникодовых текстах является постановка в начале специального символа BOM ( byte order mark , маркер последовательности байтов , U+FEFF) — «перевёрнутый» вариант этого символа (U+FFFE) не существует и не допускается в текстах.

Символ U+FEFF изображается в UTF-16 последовательностью байтов 0xFE 0xFF (big-endian) или 0xFF 0xFE (little-endian), а в UTF-32 — последовательностью 0x00 0x00 0xFE 0xFF (big-endian) или 0xFF 0xFE 0x00 0x00 (little-endian).

Проблемы совместимости и конверсии

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

Для преобразования между сетевым порядком байтов ( англ. network byte order), который всегда big-endian, и порядком байтов, использующимся на машине ( англ. host byte order), стандарт POSIX предусматривает функции htonl() , htons() , ntohl() , ntohs() :

  • uint32_t htonl(uint32_t hostlong); — конвертирует 32-битную беззнаковую величину из локального порядка байтов в сетевой;
  • uint16_t htons(uint16_t hostshort); — конвертирует 16-битную беззнаковую величину из локального порядка байтов в сетевой;
  • uint32_t ntohl(uint32_t netlong); — конвертирует 32-битную беззнаковую величину из сетевого порядка байтов в локальный;
  • uint16_t ntohs(uint16_t netshort); — конвертирует 16-битную беззнаковую величину из сетевого порядка байтов в локальный.

В случае совпадения текущего порядка байтов и сетевого функции отработают как «пустые» — то есть порядок байтов не поменяется. Стандарт также допускает, чтобы эти функции были реализованы в виде макросов.

Существует много языков и библиотек со средствами конвертации в оба основных порядка байтов и обратно.

Ядро Linux : le16_to_cpu() , cpu_to_be32() , cpu_to_le16p() , и так далее;

Ядро FreeBSD : htobe16() , le32toh() , и так далее;

Erlang :

 <<Count:32/big-unsigned-integer, Average:64/big-float>> = Chunk Message = <<Length:32/little-unsigned-integer, MType:16/little-unsigned-integer, MessageBody>> 

Python :

 import struct Count, Average = struct.unpack(">Ld", Chunk) Message = struct.pack("<LH", Length, MType) + MessageBody 

Perl :

 ($Count, $Average) = unpack('L>d>', $Chunk); $Message = pack('(LS)<', $Length, $MType) . $MessageBody; (или то же самое: $Message = pack('Vv', $Length, $MType) . $MessageBody;) 

данные примеры для Erlang, Python, Perl содержат идентичную функциональность.

Процессоры Intel x86-64 имеют инструкцию BSWAP для смены порядка байтов.

Этимология названия

Термины big-endian и little-endian первоначально не имели отношения к информатике. В сатирическом произведении Джонатана Свифта « Путешествия Гулливера » описываются вымышленные государства Лилипутия и Блефуску, в течение многих лет ведущие между собой войны из-за разногласия по поводу того, с какого конца следует разбивать варёные яйца . Тех, кто считает, что их нужно разбивать с тупого конца, в произведении называют Big-endians («тупоконечники»).

Споры между сторонниками big-endian и little-endian в информатике также часто носят характер т. н. «религиозных войн». Термины big-endian и little-endian ввёл ( англ. ) в 1980 году в своей статье «On Holy Wars and a Plea for Peace» («О священных войнах и призыв к миру»).

См. также

Примечания

  1. (неопр.) . Дата обращения: 20 декабря 2010. 13 декабря 2010 года.
  2. (неопр.) . Дата обращения: 3 августа 2008. Архивировано из 10 ноября 2006 года.
  3. Danny Cohen. (англ.) (1 апреля 1980). Дата обращения: 24 января 2010. 15 февраля 2012 года.
  4. Таненбаум Э. Архитектура компьютера. — 5-е изд. — СПб. : Питер, 2007. — 844 с. — С. 89.

Ссылки

  • от 19 февраля 2015 на Wayback Machine
  • (недоступная ссылка с 18-04-2021 [926 дней])

Same as Порядок байтов