Як комп'ютер визначає тип даних байта?


31

Наприклад, якщо комп'ютер 10111100зберігається на одному конкретному байті оперативної пам'яті, як комп'ютер знає інтерпретувати цей байт як ціле число, символ ASCII або щось інше? Чи зберігаються дані типу в сусідньому байті? (Я не думаю, що це було б так, оскільки це призвело б до використання вдвічі більше місця на один байт.)

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

Я на правильному шляху?


4
Як бічна примітка: Якщо ви говорите про типи, ви повинні робити це в мовному контексті. Компілятору залишається обробляти такі речі (символи, типи перевірок, операції, кастинг, адресний таран тощо). CPU і RAM знає тільки байт
джинсової

4
Тип даних байта - байт. Крім того, комп'ютер нічого не знає. Програма може інтерпретувати байт або групу байтів як певний тип даних і намагатися виконувати операції над ними, але обмежень там немає. Одна і та ж група байтів може бути інтерпретована як більш ніж один тип даних (тобто, введення покажчиків на типи значень, C-подібні об'єднання тощо). Те, що оперативна пам’ять не читається послідовно, насправді не має значення. - Це більше, тому що оперативна пам’ять є загальним призначенням. - Наприклад, регістри також не читаються послідовно, але вони набираються.
BrainSlugs83

5
Безсоромний штекер для себе, але це питання в основному було задано програмістам SE близько місяця тому. Ось моя відповідь на це . На даний момент це довго, але атакує його з різних кутів.
Шаз

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

@ BrainSlugs83, ви можете розглянути можливість перетворення цього відповіді?
DW

Відповіді:


38

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

Програміст має зрозуміти її дані. Процесор виконує лише доручення, не знаючи їх значення та цілей.


1
Що стосується "коли аргументи семантично підписуються або не підписуються", як би це знав ЦП? Операції з процесором просто бачать параметри байтів і не мають такого типу даних про контекстну обізнаність. Ви маєте на увазі тип даних, вибравши відповідну операцію з процесором (або ваш компілятор).
Шив

4
@Shiv У таких випадках ЦП насправді видає іншу інструкцію обробляти підписані номери проти непідписаних чисел. Як і у підозрах ОП, програма зобов'язана надати ці деталі, оскільки ЦП не знає.
Корт Аммон - Відновіть Моніку

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

1
@Loupax Ну, а робота з дійсно низьким рівнем монтажу допомагає небагато - навіть mov al, 42це на високому рівні - очевидно, що є лише одна можлива інструкція, яку це може закликати, але вона все ще дещо абстрагується. Однак mov.8 al, 42явне використання цього робить болісно очевидним :)
Luaan

1
@Shiv: Я хотів би зазначити, що є машини, де дані в пам'яті вводяться. Вони називаються архітектурами з міткою пам’яті (або просто поміченими архітектурами), але вони не були настільки успішними комерційно, як звичайні архітектури, почасти тому, що зараз ми програмуємо в основному на компільованих мовах, а не на складанні, і компілятор піклується про введення тексту. Дивіться: en.wikipedia.org/wiki/Tagged_architecture
slebetman

14

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

Однак є й інші можливості. Наприклад, машини машини Lisp використовували мічену архітектуру, яка зберігала тип кожної позиції пам'яті; таким чином апаратне забезпечення могло б виконати певну роботу на мовах високого рівня.

І навіть зараз, я думаю, ви могли б розглянути біт NX в Intel, AMD, ARM та інших архітектурах за таким же принципом: розрізняйте на апаратному рівні, чи містить дана зона пам'яті дані чи інструкції.

Крім того, лише для повноти в Гарвардській архітектурі (як і деякі мікроконтролери) фізично розділені дані та інструкції, тому процесор має певне уявлення про те, що він читає.

У цьому запитанні Quora є коментар до того, як працювала позначена пам’ять, її наслідки та зменшення продуктивності тощо.


Помічена архітектура - цікава примітка. Це було б значно швидше?
Басинатор


3

Анотації типу немає.
Оперативна пам’ять зберігає чисті дані, а потім програма визначає, що робити.

З регістрами процесора трохи складніше, якщо у вас є регістри даного типу (наприклад, FPU), ви кажете, що знаходиться всередині.
Операції з регістрами з плаваючою комою явно використовують введені дані. Ви або ваш упорядник розповідаєте, що і коли слід поставити туди, щоб у вас не було такої свободи.
Комп'ютер не робить жодних припущень щодо базових даних в оперативній пам’яті, а в регістрах за одним винятком - типові типи регістрів у процесорі відомих типів, оптимізовані для роботи з ними. Це лише для того, щоб показати, що є місця, де слід очікувати тип даних, але ніщо не зупиняє вас від метання рядків до плаваючих та їх примноження.

У мовах програмування ви вказуєте тип, або в мовах вищого рівня дані загальні, а компілятор / інтерпретатор / VM кодує те, що знаходиться всередині з накладними.
Наприклад, на C ваш тип вказівника повідомляє, що робити з даними, як отримати доступ до них.

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


Навіть біти в реєстрі FPU не завжди представляють значення з плаваючою комою. За старих часів (можливо, вже не так вже й багато?) Загальною оптимізацією було використання регістрів з плаваючою комою (64-біт або більше) для копіювання даних швидше, ніж регістри загального призначення / цілих чисел (32-розрядні), будучи вдвічі більшими, вони, як правило, могли скопіювати дані вдвічі швидше.
Сет

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

@HCBPshenanigans є інструкції, що керують значеннями з плаваючою комою. Якщо використовується FADD, має сенс лише те, що (4,8 або 10) -байтові групи пам'яті містили номери з плаваючою комою. Це справедливо для декількох типів інструкцій: множати два цілих числа має сенс лише, якщо вони є цілими числами, стрибок має сенс, лише якщо це адреса.
JDługosz

@seth і evilJS, як вважається, це не стосується застарілої плаваючої точки з вмістом 8087 інструкцій, але це стосується нових реєстрів CIMD, які можуть використовуватися просто для завантаження / збереження без інтерпретації (хоча вони повинні бути вирівняні), і застереження що якщо регістри CIMD ніколи не використовувалися, їх не потрібно зберігати в контекстному комутаторі. Якщо ви (лише) переміщаєте 8 байт через реєстр XMM, це чиста втрата, оскільки весь набір потрібно зберегти.
JDługosz

3

Процесор не хвилює, він виконує код складання, який просто переміщує дані навколо, зміщує їх, додає або множить ...

Типи даних - це концепція мови вищого рівня: у C або C ++ вам потрібно вказати типи для кожної частини даних, якими ви маніпулюєте; компілятор C / C ++ піклується про перетворення цих фрагментів даних у правильні команди для процесора (компілятори пишуть збірний код)

У деяких мовах вищого рівня можуть бути зроблені типи: наприклад, у Python або Javascript не потрібно вказувати типи даних, але дані мають тип, і ви не можете додати рядок з цілим числом, але ви можете додати float з цілим числом: "компілятор" (який у випадку Javascript - компілятор JIT (Just in Time). Javascript часто називають "інтерпретованою" мовою, оскільки історичні браузери інтерпретували код Javascript, але сьогодні двигуни Javascript є компіляторами.

Код, завжди закінчується компіляцією до машинного коду, але очевидно, що формат машинного коду залежить від машини, на яку ви орієнтуєтесь (x86 64-бітовий код не працюватиме на 32-бітній машині x86 або процесорі ARM, наприклад)

Таким чином, насправді дуже багато шарів бере участь у виконанні інтерпретованого коду.

Java та C # - інші цікаві, оскільки код Java або C # технічно "компілюється" у двійковий код Java (байт-код), але сам цей код інтерпретується Java Runtime, який є специфічним для базового обладнання (потрібно встановити JRE, орієнтований на потрібну машину для запуску бінарних файлів Java (Jars))


Компілятор компілює, будь то JIT чи ні; а інтерпретатор інтерпретує без компіляції (адже якби не, це був би компілятор!). Вони дуже різні речі. А щодо "Ява смішна" через інтерпретацію байт-коду, врахуйте, що навіть мікропроцесор x86 насправді буде інтерпретований (або навіть скомпільований?) Самим мікропроцесором у мікрокод .
hmijail

Дякую за роз’яснення ... Домовились: компілятор компілює, а інтерпретатор інтерпретує. У випадку з Javascript, хоча історія є дещо складною, оскільки деякі старші браузери інтерпретують код, тоді як більш сучасні браузери насправді компілюють своєчасно, тому, ймовірно, його досі називають "інтерпретованою" мовою, хоча вона технічно вже немає.
MrE

Але AFAIK, JS починає інтерпретуватись, а потім може бути складений за потребою. І JIT можуть переходити від інтерпретованих до компільованих до знову інтерпретованих, залежно від багатьох речей. Наприклад, фрагмент коду може бути складений для змінної, що має заданий тип; але потім код запускається знову з тією змінною, яка має інший тип, тому існуючий скомпільований код не може бути використаний, тому інтерпретатор заскакує - поки код не буде скомпільований знову для нового типу ...
hmijail

Ви цитуєте мене про те, що я не сказав, будь ласка, видаліть його, оскільки це абсолютно неправильно. Мікрокод не має нічого спільного з ОС; це щось внутрішнє для мікропроцесора. 32-бітний або 64-бітний також не мають нічого спільного.
hmijail

3

Типи даних не є апаратною функцією. Процесор знає пару (ну, багато) різних команд. Вони називаються набором інструкцій ЦП.

Один з найвідоміших - набір інструкцій x86 . Якщо ви шукаєте "помножити" на цій сторінці, ви отримаєте 50 результатів. MULPDі MULSDдля множення подвоєнь, FIMULдля цілого множення, ...

Ці команди працюють над регістрами. Регістри - це слоти пам'яті, які можуть містити фіксовану кількість біт (часто 32 або 64, залежно від архітектури, яку використовує ваш процесор), незалежно від того, що представляють ці біти. Отже інструкція CPU трактує значення регістрів по-іншому, але самі значення не мають типів.

Приклад подав на PyCon 2017 Стюарт Вільямс :

введіть тут опис зображення


1
Зауважте, що це не зовсім вірно: є регістри спеціального призначення, які не можуть містити довільних значень (наприклад, регістри вказівників, які не є просто будь-якою адресою та не дозволяють довільних доповнень, або регістри з плаваючою точкою, де можна не зберігати ненормовані значення). Але ваша відповідь правильна для регістрів загального призначення для більшості архітектур.
Жил "ТАК - перестань бути злим"

2

... що певна програма просто повідомляє процесору отримати інформацію з певної адреси, і програма визначає, як з цим поводитися.

Саме так. Але оперативна пам'ять не читається "послідовно", і вона розшифровується як пам'ять випадкового доступу, що прямо навпаки.

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

Я хотів би додати інші відповіді, наводячи конкретні приклади.

Розглянемо 01000001. Програма може скопіювати її з одного місця в інше як частину великої посилки даних, не зважаючи на її значення. Але, якщо скопіювати його на адресу, яку використовується текстовим буфером текстового режиму, це відображатиме лист Aу певному положенні на екрані. Точно така ж дія, коли карта знаходиться в графічному режимі CGA, відображатиме червоний піксель і синій піксель.

У реєстрі це може бути число 65 як ціле число. Виконання арифметики для встановлення біта 32 може означати що завгодно без контексту, але конкретно може бути зміна літери на малі регістри.

Процесор 8086 (досі) має спеціальні інструкції під назвою DAA ※, які використовуються, коли реєстр містить дві десяткові цифри, тому якщо ви щойно використовували цю інструкцію, ви інтерпретуєте її як дві цифри 41.

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

За допомогою налагоджувача, перевірки пам’яті, використовується карта , яка спрямовує інтерпретацію для відображення. Без цієї символьної інформації налагоджувач низького рівня дозволяє вам вказати: показувати цю адресу як 16-бітні слова, показувати цю адресу як довгу плаваючу точку, як рядки ... як завгодно. Дивлячись на дамп мережевого пакету або невідомий формат файлу, розгадування його є проблемою.

Це головне джерело потужності та гнучкості в сучасній архітектурі комп’ютера: осередок пам'яті може означати що завгодно , дані або інструкції, мається на увазі лише в тому, що це "означає" для програми через те, що вона робить зі значенням і як це впливає на подальші операції. сенс глибший від цілої ширини: це символи ... символи в ascii чи ebcdic? Формування слів англійською мовою чи кодами SQU? Адреса, яку потрібно надіслати або зворотну адресу, з якої вона надійшла? Найнижчий рівень інтерпретації (логічні біти, ціле число типу, знаком або без знаку; поплавок; BCD; покажчик) контекстна на рівні набору команд, але ви бачите , що це все контекст на якому - то рівні: вАдреса - це те, що вона є через розташування, яке друкується на конверті. Це контекстуально до правил листоноші, а не до процесора. Контекст - це один великий континуум, з бітами на одному його кінці.


※ Зноска: інструкція DAA кодується як байт 00100111. Отже, цей байт - це вищезазначена інструкція, якщо її читати в потоці інструкцій, а цифри, 27якщо інтерпретувати як bcd цифри, а 0x27 = 39 як ціле число, яке є цифрою 9 в ASCII, і частина таблиці переривання (половина INT 13 2-байтна адреса, що використовується для процедур обслуговування BIOS).


1

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.