Яка перевага формату маленького ендіану?


140

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

Мені завжди цікаво, чому хтось хотів би зберігати байти у зворотному порядку. Чи має цей формат якісь переваги перед великим ендіанським форматом?


1
6502 був раннім (першим?) Конвеєрним процесором. Я, мабуть, пам’ятаю певну претензію на те, що вона є малопомітною для деяких проблем, пов’язаних з роботою, пов'язаних з роботою, але я не маю уявлення, що це могло бути. Будь-які пропозиції?
Steve314

1
@ Steve314: У моїй відповіді пояснюється, як маленький ендіан допомагає виконувати продуктивність у конвеєрному процесорі: programmers.stackexchange.com/q/95854/27874
Martin Vilcans

3
Маленький-ендіанський, великий-ендіанський - ви повинні вибрати те чи інше. Як і їхати ліворуч або праворуч дороги.

3
Я пропоную вам написати якийсь код в ASM, бажано для архітектури "old-school", наприклад 6502 або Z80. Ви одразу побачите, чому в них використовується мало ендіану. Архітектури, які використовують великий ендіан, мають певні характеристики свого набору інструкцій, що робить цей формат кращим. Це не довільне рішення приймати!
Стефан Пол Ноак

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

Відповіді:


198

Існують аргументи в будь-якому випадку, але один момент полягає в тому, що в системі мало ендіанів адреса заданого значення в пам'яті, прийнята як 32, 16 або 8 бітова ширина, однакова.

Іншими словами, якщо у вас є в пам'яті значення двох байтів:

0x00f0   16
0x00f1    0

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

У системі з великим ендіаном, із зазначеним вище:

0x00f0    0
0x00f1   16

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

Отже, коротше кажучи, "у маленьких ендіанських системах касти є неоперативними".


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

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

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

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

4
@dan_waterworth не зовсім - майте на увазі, наприклад, арифметичні правила вказівника на C, наприклад, і що відбувається, коли ви збільшуєте чи зменшуєте викиди того ж покажчика. Ви можете перемістити складність, але ви не можете її усунути.
jimwise

45

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

Біг-ендіан і малий-ендіан - це лише "нормальний порядок" і "зворотний порядок" з точки зору людини, і тільки тоді, якщо все це правдиво ...

  1. Ви читаєте значення на екрані або на папері.
  2. Ви ставите нижчі адреси пам'яті зліва, а вищі - праворуч.
  3. Ви пишете шістнадцятковою формою, з найменшим плетінням зліва або бінарним, з найбільш значущим бітом ліворуч.
  4. Ви читаєте зліва направо.

Це все людські конвенції, які взагалі не мають значення для процесора. Якби ви зберегли №1 та №2 та перевернули №3, маленький ендіанець здавався б "цілком природним" людям, які читають арабською чи івритом, які написані справа наліво.

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

  • "Більш" (найзначніший) байт повинен бути за адресою "вищої" пам'яті.

Ще коли я програмував 68K та PowerPC, я вважав, що big-endian є "правильним", а little-endian - "неправильним". Але оскільки я займаюся більшою роботою ARM та Intel, я звик до маленьких ендіян. Це насправді не має значення.


30
Числа насправді записуються від [найбільш значної цифри] зліва до [найменш значної цифри] правою арабською та івритською мовами.
Випадково832

5
Тоді чому біти в байті зберігаються у форматі "великий ендіан"? Чому б не бути послідовним?
tskuzzy

11
Вони не є - біт 0 за умовою є найменш значущим, а біт 7 - найбільш значущим. Крім того, ви не можете розміщувати замовлення на біти в байті, оскільки біти не адресовані індивідуально. Звичайно, вони можуть мати фізичний порядок у певному протоколі зв'язку або носії інформації, але якщо ви не працюєте на протоколі низького рівня або апаратному рівні, вам не потрібно займатися цим замовленням.
Стюарт

3
BlueRaja: тільки за умовами написання на папері. Це не має нічого спільного з архітектурою процесора. Ви можете записати байт як 0-7 LSB-MSB замість 7-0 MSB-LSB, і нічого не змінюється з точки зору алгоритму.
СФ.

2
@SF. "Натисніть коротко, попсете що завгодно, але коротке " все одно ви отримаєте сюрприз. Навіть якщо ви не пошкоджуєте стек, натисканням байтів, ви ніколи не вискочуєте або навпаки ... Наприклад, x86 (32-розрядний) дуже хоче, щоб стек був вирівняний у слові, а також натискав або вискакував усе, що спричиняє покажчик стека, щоб не бути кратним 4, може спричинити проблеми з вирівнюванням. І навіть якщо цього не сталося, речі одночасно підштовхували ціле слово / dword / qword / тощо - тому низький байт все одно буде першим, який ви отримаєте, коли ви з'явитеся.
cHao

41

Гаразд, ось чому я пояснив мені причину: Додавання і віднімання

Коли ви додаєте або віднімаєте багатобайтові числа, вам слід почати з найменш значущого байта. Якщо ви додаєте, наприклад, два 16-бітні числа, може бути перенесення від найменш значущого байта до найзначнішого байта, тому вам доведеться почати з найменш значущого байта, щоб побачити, чи є перенос. Це та сама причина, що ви починаєте з правої цифри під час складання з великої руки. Не можна починати зліва.

Розглянемо 8-бітну систему, яка послідовно отримує байти з пам'яті. Якщо він спочатку отримує найменш значущий байт , він може почати робити додавання, тоді як найзначніший байт видобувається з пам'яті. Цей паралелізм є причиною того, що продуктивність краща у маленьких ендіян на таких, як система. Якби довелося чекати, поки обидва байти витягнуті з пам'яті або отримати їх у зворотному порядку, це займе більше часу.

Це в старих 8-бітних системах. У сучасному процесорі я сумніваюся, що порядок байтів має будь-яке значення, і ми використовуємо мало ендіанів лише з історичних причин.


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

2
Думка - 6502 не робив багато 16-бітної математики в апаратному забезпеченні - це, зрештою, 8-бітний процесор. Але це було відносною адресацією, використовуючи 8-бітові зсуви, підписані відносно 16-бітної базової адреси.
Steve314

2
Зауважте, що ця ідея все ще має значення для множинної арифметики з великою точністю (як сказав Стів314), але на рівні слів. Тепер, на більшість операцій безпосередньо не впливає витривалість процесора: все-таки можна зберігати найменш значуще слово спочатку в системі big-endian, як це робив GMP. Процесори маленьких ендіанів все ще мають перевагу в кількох операціях (наприклад, кілька перетворень рядків?), Які можна простіше зробити, прочитавши по одному байту, оскільки лише в системі з маленьким ендіаном впорядкування байтів таких чисел є правильним.
vinc17

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

13

З 8-бітовими процесорами це було, безумовно, більш ефективно, ви можете виконати 8 або 16-бітну операцію, не потребуючи іншого коду та не потребуючи буферування додаткових значень.

Ще краще для деяких операцій додавання, якщо ви одночасно займаєтеся байтом.

Але немає причин, що біг-ендіан є більш природним - в англійській мові ви використовуєте тринадцять (маленький ендіан) і двадцять три (великий ендіан)


1
Біг-ендіан справді простіший для людей, оскільки він не потребує перестановки байтів. Наприклад, на ПК 0x12345678зберігається як у 78 56 34 12той час, як у системі BE це 12 34 56 78(байт 0 - зліва, байт 3 - справа). Зверніть увагу, чим більша кількість (у бітах), тим більше потрібно їх заміни; WORD вимагатиме однієї заміни; DWORD, два проходи (три загальних свопи); QWORD три проходи (7 усього) тощо. Тобто, (bits/8)-1свопи. Інший варіант - читання їх як вперед, так і назад (читання кожного байта вперед, але сканування всього # назад).
Synetech

Сто тринадцять - це або середній, або інший великий-ендіанець, "тринадцять" - це по суті одна недесяткова цифра. Коли ми пишемо цифри, є деякі незначні відхилення від конвенцій постійної бази, які ми використовуємо для цифр, але як тільки ви викреслите ці особливі випадки, решта - це великі ендіанти - мільйони до тисяч, тисячі до сотні тощо.
Steve314

@ Synetech - на щастя, комп'ютер не повинен дбати, як люди їх читають. Це як би стверджувати, що спалах NAND кращий, тому що від '
Мартін Бекетт

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

@ steve314 А в датській мові "95" вимовляється "fem halvfems" (п'ять плюс чотири з половиною двадцятих років).
Ватін

7

Японська конвенція про дату є "великою ендіанською" - yyyy / мм / дд. Це зручно для алгоритмів сортування, в яких можна використовувати просте рядкове порівняння зі звичайним правилом першого символу - це найзначніше.

Щось подібне стосується і номерів великих ендіанів, які зберігаються в найбільш значущому першому полі запису. Порядок значущості байтів у полях відповідає значенню полів у записі, тому ви можете використовувати a memcmpдля порівняння записів, не піклуючись, чи порівнюєте ви два довгих слова, чотири слова чи вісім окремих байтів.

Переверніть порядок значущості полів, і ви отримаєте ту ж перевагу, але для малих-ендіанських чисел, а не для великих-ендіанів.

Це, звичайно, має дуже мало практичного значення. Незалежно від того, чи є ваша платформа великим або маленьким, ви можете замовити поля записів, щоб використовувати цей трюк, якщо вам це справді потрібно. Це просто біль, якщо вам потрібно написати портативний код.

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

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

EDIT

Зайва думка. Я колись написав велику цілочисельну бібліотеку (щоб побачити, чи зможу я), і для цього 32-бітні шматки зберігаються в малопомітному порядку, незалежно від того, як платформа впорядковує біти в цих фрагментах. Причини були ...

  1. Дуже багато алгоритмів, природно, починають працювати в найменш значущому кінці, і хочуть, щоб ці цілі були узгоджені. Наприклад, крім того, носій пропонує все більш і більш значні цифри, тому є сенс починати з найменш значущого кінця.

  2. Зростання або зменшення значення означає лише додавання / видалення шматочків наприкінці - не потрібно переміщувати шматки вгору / вниз. Копіювання все ж може знадобитися через перерозподіл пам’яті, але не часто.

Це, очевидно, не стосується процесорів, звичайно - поки процесори не створені з апаратною підтримкою великих цілих чисел, це суто бібліотечна річ.


7

Ніхто ще не відповів ЧОМУ це можна зробити, багато чого про наслідки.

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

Тепер, якщо ви хочете завантажити 16-бітове значення, скажіть (скажімо) один і єдиний у вас 16-бітний реєстр - тобто лічильник програми, то простий спосіб зробити це:

  • Завантажте байт з місця отримання
  • перемістіть цей байт вліво на 8 місць
  • збільшення місця отримання пам'яті на 1
  • завантажте наступний байт (до частини низького порядку реєстру)

результат: ви тільки коли-небудь збільшуєте місце отримання даних, ви тільки коли-небудь завантажуєтесь у низький порядок частини вашої ширшої реєстрації, і вам потрібно лише мати змогу зрушити ліворуч. (Звичайно, зсув праворуч корисний для інших операцій, тому ця частина є побічним шоу.)

Наслідком цього є те, що 16-бітний (двобайтовий) матеріал зберігається в порядку Most..Least. Тобто менша адреса має найзначніший байт - такий великий ендіан.

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

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

Іншими словами, з точки зору повернення грошей за старі часи, ви отримали більше ударів для більшої продуктивності та найменшої площі кремнію.

У наші дні ці міркування і вкрай неактуальні, але такі речі, як заливка трубопроводів, все ж можуть бути великою справою.

Що стосується написання с / ш, життя часто простіше, коли використовується мало ендіанських адрес.

(І великі ендіанські процесори, як правило, є великими ендіанами з точки зору впорядкування байтів і мало ендіанів з точки зору біт-байтів. Але деякі процесори дивні, і вони будуть використовувати великі впорядкування біт-ендіанів, а також впорядкування байтів. Це робить життя дуже цікаво для дизайнера, що додає ч / б додавання периферійних пристроїв, орієнтованих на пам'ять, але це не має іншого наслідку для програміста.)


3

jimwise зробив хороший момент. Є ще одне питання: у маленьких ендіанів ви можете зробити наступне:

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: в моїй книзі краще віднімання на менше
Cem Kalyoncu,

Це не має значення, оскільки компілятор все одно розкрутить цикл. У будь-якому випадку, багато процесорів мають інструкції з заміни байтів для вирішення цієї проблеми.
Мартін Вілканс

Я не згоден bcoz на великому ендіані, я б зробив {num << = 8; num | = дані [i]; } принаймні для цього не потрібно підраховувати кількість лівої зміни, використовуючи mul
Hayri Uğur Koltuk

@ali: ваш код виконає точну операцію, яку я написав, і не працюватиме на великому ендіані.
Cem Kalyoncu

1

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

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

1234

є тисяча, двісті тридцять чотири.

Таким чином, великий ендіан іноді називають природним порядком.

У маленькому ендіані це число склало б одну, двадцять, триста чотири тисячі.

Однак, виконуючи такі арифметичні, як додавання чи віднімання, ви починаєте з кінця.

  1234
+ 0567
  ====

Ви починаєте з 4 і 7, пишете найнижчу цифру і запам'ятовуєте перенесення. Потім ви додаєте 3 і 6 і т. Д. Для додавання, віднімання або порівняння їх простіше реалізувати, якщо ви вже маєте логіку для читання пам'яті в порядку, якщо числа перевернуті.

Щоб підтримати великий ендіан таким чином, вам потрібна логіка для читання пам'яті в зворотному порядку, або у вас є RISC-процес, який працює тільки на регістри. ;)

Багато дизайну Intel x86 / Amd x64 є історичним.


0

Біг-ендіан є корисним для деяких операцій (порівняння "bignums" однакової довжини октету довжиною до душі). Літ-ендіан для інших (додавання, можливо, двох "бінгумів"). Зрештою, це залежить від того, для чого було встановлено апаратне забезпечення процесора, як правило, це те чи інше (деякі мікросхеми MIPS були, IIRC, з перемиканням на завантаження, щоб бути LE або BE).


0

Якщо задіяні лише зберігання та передача зі змінною довжиною, але немає арифметики з кількома значеннями, тоді LE зазвичай простіше писати, тоді як BE легше читати.

Візьмемо конкретний приклад int-string-перетворення (і назад).

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.