В чем преимущество формата с прямым порядком байтов?


140

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

Мне всегда интересно, почему кто-то захочет хранить байты в обратном порядке. Есть ли у этого формата какие-либо преимущества перед форматом с прямым порядком байтов?


1
6502 был ранним (первым?) Конвейерным процессором. Кажется, я помню некоторые утверждения о том, что он является прямым порядком для некоторой проблемы, связанной с производительностью из-за конвейера, - но сейчас я понятия не имею, какой могла быть эта проблема. Какие-либо предложения?
Steve314

1
@ Steve314: Мой ответ объясняет, как littleianian помогает с производительностью в конвейерном процессоре: programmers.stackexchange.com/q/95854/27874
Мартин Вилканс

3
Little-endian, big-endian - вы должны выбрать один или другой. Как езда по левой или правой стороне дороги.

3
Я предлагаю вам написать некоторый код на ASM, предпочтительно для архитектуры "старой школы", такой как 6502 или Z80. Вы сразу поймете, почему в них используется порядок байтов. Архитектуры, в которых используется порядок байтов, имеют определенные характеристики в своем наборе команд, которые делают этот формат предпочтительным. Это не произвольное решение!
Стефан Пол Ноак

2
Каждая система заказа байтов имеет свои преимущества. Машины с прямым порядком байтов позволяют сначала прочитать младший байт, не читая остальные. Вы можете легко проверить, является ли число нечетным или четным (последний бит равен 0), что здорово, если вы любите подобные вещи. Системы с прямым порядком байтов хранят данные в памяти так же, как мы, люди, думаем о данных (слева направо), что облегчает низкоуровневую отладку.
Корай Тугай

Ответы:


198

В любом случае, существуют аргументы, но одна из них заключается в том, что в системе с прямым порядком байтов адрес определенного значения в памяти, принимаемого за 32, 16 или 8 бит, одинаков.

Другими словами, если у вас в памяти есть двухбайтовое значение:

0x00f0   16
0x00f1    0

Принятие этого '16' в качестве 16-битного значения (c 'short' в большинстве 32-битных систем) или в качестве 8-битного значения (обычно c 'char') изменяет только используемую вами команду извлечения - не адрес, который вы выбираете из.

В системе с прямым порядком байтов, с вышеизложенным выложенным как:

0x00f0    0
0x00f1   16

вам нужно будет увеличить указатель, а затем выполнить более узкую операцию извлечения нового значения.

Итак, вкратце, «в системах с прямым порядком байтов броски не нужны».


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

10
@ Steve314: Если я в C уменьшаю значение с 32 до 16 бит (например) в системе с двумя дополнительными компонентами - подавляющее большинство систем - байты не должны быть равны нулю, чтобы их игнорировать. Независимо от их ценности, я могу игнорировать их и оставаться совместимым со стандартом C и ожиданиями программистов.

9
@Stritzinger - мы говорим о сборке / машинном коде, сгенерированном компилятором, который не может быть переносимым. Код языка более высокого уровня для компиляции переносим - он просто компилируется для разных операций на разных архитектурах (как это делают все ops).
Jimwise

7
Я не покупаю этот аргумент, потому что на архитектурах с прямым порядком байтов указатель может указывать на конец, а не на начало того, на что вы ссылаетесь и чем у вас будет точно такое же преимущество.
dan_waterworth

4
@dan_waterworth не совсем - имейте в виду, например, арифметические правила указателя в C и то, что происходит, когда вы увеличиваете или уменьшаете приведение одного и того же указателя. Вы можете переместить сложность, но вы не можете устранить ее.
Jimwise

45

Мне всегда интересно, почему кто-то захочет хранить байты в обратном порядке.

Big-endian и little-endian - это только «нормальный порядок» и «обратный порядок» с человеческой точки зрения, и только в том случае, если все это верно ...

  1. Вы читаете значения на экране или на бумаге.
  2. Вы помещаете младшие адреса памяти слева, а верхние справа.
  3. Вы пишете в шестнадцатеричном виде, с левым верхним порядком nybble или в двоичном, с самым старшим битом слева.
  4. Вы читаете слева направо.

Это все человеческие соглашения, которые не имеют никакого значения для процессора. Если бы вы сохранили # 1 и # 2 и перевернули # 3, little-endian показался бы «совершенно естественным» людям, которые читают по-арабски или на иврите, которые написаны справа налево.

И есть другие человеческие соглашения, которые делают big-endian кажущимися неестественными, как ...

  • «Старший» (самый значимый) байт должен находиться на «старшем» адресе памяти.

Когда я в основном программировал 68K и PowerPC, я считал, что big-endian «правильный», а little-endian «неправильный». Но так как я больше работал над ARM и Intel, я привык к порядку байтов. Это действительно не имеет значения.


30
Цифры на самом деле пишутся от [самой значимой цифры] слева до [наименее значимой цифры] справа на арабском и иврите.
Random832

5
Тогда почему биты внутри байта хранятся в формате "с прямым порядком байтов"? Почему бы не быть последовательным?
tskuzzy

11
Это не так - бит 0 считается наименее значимым, а бит 7 - наиболее значимым. Более того, вы не можете обычно размещать порядок в битах внутри байта, так как биты не адресуются индивидуально. Конечно, они могут иметь физический порядок в данном протоколе связи или на носителе, но если вы не работаете на низкоуровневом протоколе или аппаратном уровне, вам не нужно беспокоиться об этом порядке.
Стюарт

3
BlueRaja: только по соглашению написания на бумаге. Это не имеет ничего общего с архитектурой процессора. Вы можете записать байт как 0-7 LSB-MSB вместо 7-0 MSB-LSB, и ничего не меняется с точки зрения алгоритма.
SF.

2
@SF .: «Толкни коротко, вставь что-нибудь, кроме короткого », ты все равно будешь удивлен. Даже если вы не повреждаете стек, выдвигая байты, вы никогда не выскакиваете, или наоборот ... x86 (32-разрядная версия ), на самом деле , действительно хочет, чтобы стек был выровнен по dword, и выталкивал или выталкивал все, что вызывает указатель стека, не кратный 4, может вызвать проблемы с выравниванием. И даже если этого не произойдет, материал выдвинет за раз целое слово / dword / qword / etc - так что младший байт все равно будет первым, который вы получите, когда вы щелкаете.
Цао

41

Хорошо, вот причина, как я объяснил мне: сложение и вычитание

Когда вы добавляете или вычитаете многобайтовые числа, вы должны начинать с младшего байта. Например, если вы добавляете два 16-разрядных числа, может быть перенос от наименее значимого байта к старшему значащему, поэтому вам нужно начать с наименее значимого байта, чтобы увидеть, есть ли перенос. Это та же самая причина, по которой вы начинаете с самой правой цифры при добавлении от руки. Вы не можете начать слева.

Рассмотрим 8-битную систему, которая последовательно выбирает байты из памяти. Если он сначала выбирает младший значащий байт , он может начать добавление, пока самый старший байт извлекается из памяти. Этот параллелизм является причиной того, что производительность в порядке с прямым порядком байтов выше, чем в системе. Если бы пришлось ждать, пока оба байта были извлечены из памяти, или извлечь их в обратном порядке, это заняло бы больше времени.

Это на старых 8-битных системах. На современном процессоре я сомневаюсь, что порядок байтов имеет какое-либо значение, и мы используем little-endian только по историческим причинам.


3
Ах, так что это примерно та же самая причина, по которой я использую порядок байтов с прямым порядком байтов для больших целых чисел. Я должен был решить это. Люди действительно должны получить работу по кибернетике в настоящее время - мой мозг уже остро нуждается в некоторых запасных частях и некоторых радикальных модернизаций, я не могу ждать вечно!
Steve314

2
Мысль - 6502 не делал много 16-битной математики в аппаратном обеспечении - это был, в конце концов, 8-битный процессор. Но он делал относительную адресацию, используя 8-битные смещения со знаком относительно 16-битного базового адреса.
Steve314

2
Обратите внимание, что эта идея все еще имеет значение для целочисленной арифметики с множественной точностью (как сказал Steve314), но на уровне слова. Теперь на большинство операций напрямую не влияет порядковый номер процессора: все еще можно сначала сохранить наименее значимое слово в системе с прямым порядком байтов, как это делает GMP. Процессоры с прямым порядком байтов по-прежнему имеют преимущество в отношении нескольких операций (например, некоторых преобразований строк?), Которые легче выполнить, считывая по одному байту за раз, поскольку только в системе с прямым порядком байтов порядок байтов таких чисел является правильным.
vinc17

Процессоры с прямым порядком байтов имеют преимущество в случае, если пропускная способность памяти ограничена, как в некоторых 32-битных процессорах ARM с 16-битной шиной памяти или в 8088 с 8-битной шиной данных: процессор может просто загрузить младшую половину и выполнить добавьте / sub / mul ... вместе с ним в ожидании верхней половины
phuclv

13

С 8-битными процессорами это было, безусловно, более эффективно, вы могли выполнять 8- или 16-битные операции без необходимости в другом коде и без буферизации дополнительных значений.

Еще лучше для некоторых операций сложения, если вы обрабатываете байт за раз.

Но нет никакой причины, по которой big-endian более естественен - ​​в английском языке вы используете тринадцать (little-endian) и двадцать три (big endian)


1
Big-endian действительно проще для людей, потому что он не требует перестановки байтов. Например, на ПК 0x12345678хранится как, 78 56 34 12тогда как в системе BE это 12 34 56 78(байт 0 слева, байт 3 справа). Обратите внимание, что чем больше число (в битах), тем больше требуется замены; СЛОВО потребует один обмен; DWORD, два прохода (всего три обмена); QWORD три прохода (всего 7) и так далее. То есть (bits/8)-1свопы. Другим вариантом является чтение их как вперед, так и назад (чтение каждого байта вперед, но сканирование всего # назад).
Synetech

Сто тринадцать - это либо порядок байтов со средним порядком байтов, либо порядок байтов со старшим порядком, причем «тринадцать» по сути является одной недесятичной цифрой. Когда мы пишем числа, есть некоторые незначительные отклонения от соглашений о константах, которые мы используем для цифр, но как только вы отбрасываете эти особые случаи, остальное становится
порядком

@ Synetech - к счастью, компьютер не заботится о том, как люди их читают. Это все равно что утверждать, что NAND-вспышка лучше, потому что
Мартин Беккет

1
@ Steve314, прописанные слова чисел не имеют значения, это числовые показания, которые мы используем при программировании. Мартин, никаким компьютерам не нужно заботиться о том, как люди читают цифры, но если людям легко их читать, программирование (или другая связанная с этим работа) становится проще, а некоторые недостатки и ошибки можно уменьшить или избежать.
Synetech

@ steve314 А на датском языке «95» произносится как «fem halvfems» (пять плюс четыре с половиной двадцатых).
Vatine

7

Японское соглашение о дате - "big endian" - гггг / мм / дд. Это удобно для алгоритмов сортировки, которые могут использовать простое сравнение строк с обычным правилом «первый символ - самый значимый».

Нечто подобное применимо и к числам с прямым порядком байтов, хранящимся в записи с наиболее значимым полем-первым. Порядок значимости байтов в полях соответствует значению полей в записи, поэтому вы можете использовать a memcmpдля сравнения записей, не заботясь о том, сравниваете ли вы два длинных слова, четыре слова или восемь отдельных байтов.

Отразите порядок значимости полей, и вы получите то же преимущество, но для порядковых чисел, а не для порядковых.

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

Я могу также включить ссылку на классический призыв ...

http://tools.ietf.org/rfcmarkup?url=ftp://ftp.rfc-editor.org/in-notes/ien/ien137.txt

РЕДАКТИРОВАТЬ

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

  1. Многие алгоритмы естественным образом начинают работать с наименее значимой целью и хотят, чтобы эти цели были согласованы. Например, кроме того, переносы распространяются на все более и более значимые цифры, поэтому имеет смысл начинать с наименее значимого конца.

  2. Увеличение или уменьшение значения означает просто добавление / удаление фрагментов в конце - нет необходимости перемещать фрагменты вверх / вниз. Копирование все еще может быть необходимо из-за перераспределения памяти, но не часто.

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


7

Никто другой не ответил, ПОЧЕМУ это может быть сделано, много вещей о последствиях.

Рассмотрим 8-битный процессор, который может загрузить один байт из памяти за заданный тактовый цикл.

Теперь, если вы хотите загрузить 16-битное значение, скажем, в один-единственный 16-битный регистр, который у вас есть - то есть в счетчик программ, то простой способ сделать это:

  • Загрузить байт из места получения
  • сдвинуть этот байт влево на 8 мест
  • увеличить местоположение выборки памяти на 1
  • загрузить следующий байт (в младшую часть регистра)

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

Следствием этого является то, что 16-битный (двухбайтовый) материал хранится в порядке Most..Least. То есть, у меньшего адреса самый старший байт - такой большой порядок байтов.

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

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

Другими словами, с точки зрения получения отдачи в прежние времена, вы получили больше отдачи за большую производительность и наименьшую площадь кремния.

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

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

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


3

Jimwise сделал хорошую мысль. Есть еще одна проблема, в Little Endian вы можете сделать следующее:

byte data[4];
int num=0;
for(i=0;i<4;i++)
    num += data[i]<<i*8; 

OR 

num = *(int*)&data; //is interpreted as

mov dword data, num ;or something similar it has been some time

Более просты для программистов, на которых не влияет очевидный недостаток мест подкачки в памяти. Лично я нахожу, что обратный порядок байтов обратен тому, что естественно :). 12 должно храниться и записываться как 21 :)


1
Это просто доказывает, что работать быстрее / проще в любом формате, который встроен в процессор. Это ничего не говорит о том, что лучше. То же самое относится и к старому порядку байтов: for(i=0; i<4; i++) { num += data[i] << (24 - i * 8); }соответствует move.l data, numпроцессору с большим порядком байтов.
Мартин Вилканс

@martin: в моей книге лучше вычесть на одно меньше
Джем Калионку

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

я не согласен с bcoz на big endian, я бы сделал {num << = 8; num | = data [i]; } по крайней мере, для этого не нужно вычислять счетчик левого сдвига, используя муль
Хайри Угур Колтук

@ali: ваш код будет выполнять ту операцию, которую я написал, и не будет работать с прямым порядком байтов.
Джем Калионку

1

Мне всегда интересно, почему кто-то хотел бы хранить байты в обратном порядке

Десятичные числа пишутся с прямым порядком байтов. Кроме того, как вы пишете по-английски. Вы начинаете с самой значимой цифры и со следующей самой значимой до наименее значимой. например

1234

одна тысяча двести тридцать четыре.

Таким образом, большой порядок байтов иногда называют естественным порядком.

В младшем порядке, это число будет одна, двадцать, триста четыре тысячи.

Однако, когда вы выполняете арифметику, такую ​​как сложение или вычитание, вы начинаете с конца.

  1234
+ 0567
  ====

Вы начинаете с 4 и 7, пишете младшую цифру и запоминаете перенос. Затем вы добавляете 3 и 6 и т. Д. Для сложения, вычитания или сравнения проще реализовать, если у вас уже есть логика для чтения памяти по порядку, если числа поменялись местами.

Для поддержки байтового порядка таким образом, вам нужна логика для чтения памяти в обратном порядке, или у вас есть процесс RISC, который работает только с регистрами. ;)

Дизайн Intel x86 / Amd x64 во многом является историческим.


0

Big-endian полезен для некоторых операций (сравнения «bignums» одинаковых значений длины октетов). Little-endian для других (возможно, добавление двух "bignums"). В конце концов, это зависит от того, для чего было настроено аппаратное обеспечение ЦП, обычно это один или другой (некоторые микросхемы MIPS были, IIRC, переключались при загрузке, чтобы быть LE или BE).


0

Когда речь идет только о хранении и передаче с переменной длиной, но без арифметики с несколькими значениями, то LE обычно легче писать, а BE легче читать.

Давайте возьмем преобразование между строками (и обратно) в качестве конкретного примера.

int val_int = 841;
char val_str[] = "841";

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

val_int = 841;
// Make sure that val_str is large enough.

i = 0;
do // Write at least one digit to care for val_int == 0
{
    // Constants, can be optimized by compiler.
    val_str[i] = '0' + val_int % 10;
    val_int /= 10;
    i++;
}
while (val_int != 0);

val_str[i] = '\0';
// val_str is now in LE "148"
// i is the length of the result without termination, can be used to reverse it

Теперь попробуйте то же самое в порядке BE. Обычно вам нужен еще один делитель, который содержит наибольшую степень 10 для определенного числа (здесь 100). Сначала нужно найти это, конечно. Намного больше вещей, чтобы сделать.

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

val_int = 0;
length = strlen(val_str);

for (i = 0; i < length; i++)
{
    // Again a simple constant that can be optimized.
    val_int = 10*val_int + (val_str[i] - '0');
}

Теперь сделайте то же самое в порядке LE. Опять же, вам понадобится дополнительный коэффициент, начинающийся с 1 и умноженный на 10 для каждой цифры.

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

Другим примером хранилища BE будет кодировка UTF-8 и многое другое.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.