Как компьютер определяет тип данных байта?


31

Например, если компьютер 10111100хранится в одном конкретном байте ОЗУ, как компьютер узнает, что он интерпретирует этот байт как целое число, символ ASCII или что-то еще? Данные типа хранятся в соседнем байте? (Я не думаю, что это будет так, поскольку это приведет к использованию вдвое больше места для одного байта.)

Я подозреваю, что, возможно, компьютер даже не знает тип данных, что знает только программа, использующая его. Я предполагаю, что, поскольку ОЗУ является R AM и, следовательно, не читается последовательно, то конкретная программа просто говорит ЦП извлечь информацию с определенного адреса, и программа определяет, как ее обрабатывать. Казалось бы, это согласуется с такими вещами в программировании, как необходимость в типизировании.

Я на правильном пути?


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

4
Тип данных байта является байтом. Кроме того, компьютер ничего не знает. Программа может интерпретировать байт или группу байтов как определенный тип данных и пытаться выполнять операции с ними, но там нет никаких ограничений. Одну и ту же группу байтов можно интерпретировать как несколько типов данных (т. Е. Приведение указателей к типам значений, C-подобные объединения и т. Д.). То, что RAM не читается последовательно, на самом деле не имеет значения. - Это больше, потому что оперативная память общего назначения. - Регистры, например, также не читаются последовательно, но они печатаются.
BrainSlugs83

5
Бесстыдная заглушка для меня, но этот вопрос в основном задавался программистам SE около месяца назад. Вот мой ответ на это . На данный момент он довольно длинный, но атакует его с разных сторон.
Shaz

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

@ BrainSlugs83, не могли бы вы преобразовать это в ответ?
DW

Ответы:


38

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

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


1
Относительно того, «когда аргументы семантически подписаны или не подписаны», как процессор узнает? Операции ЦП просто видят байты параметров и не имеют такого рода понимания контекста типа данных. Вы подразумеваете тип данных, выбирая соответствующую операцию ЦПУ (или ваш компилятор делает).
Шив

4
@Shiv В таких случаях CPU фактически выдается другая инструкция для обработки чисел со знаком и чисел без знака. Как и в подозрениях OP, программа обязана предоставить эти детали, потому что процессор не знает.
Cort Ammon - Восстановить Монику

2
Я работаю с компьютерами до тех пор, пока себя помню, и хотя я знаю, что ЦП не заботятся о высокоуровневых конструкциях, которые мы используем при программировании на высоком уровне, но такое разделение понятий все еще пугает меня время от времени
Loupax

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

1
@Shiv: Я хотел бы отметить, что есть машины, на которых данные в памяти набираются. Они называются архитектурами с теговой памятью (или просто архитектурой с тегами), но коммерчески они не были такими же успешными, как обычные архитектуры, отчасти потому, что теперь мы программируем в основном на скомпилированных языках, а не на ассемблере, а компилятор заботится о типизации. Смотрите: en.wikipedia.org/wiki/Tagged_architecture
slebetman

14

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

Однако есть и другие возможности. Например, в Lisp Machines использовалась архитектура с тегами, в которой сохранялся тип каждой позиции в памяти; таким образом, само оборудование может выполнять некоторые функции языков высокого уровня.

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

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

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


Помеченная архитектура - интересная заметка. Будет ли это значительно быстрее?
Басинатор


3

Нет типовых аннотаций.
RAM хранит чистые данные, а затем программа определяет, что делать.

С ЦП регистры немного сложнее, если у вас есть регистры данного типа (например, 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, например, нет необходимости указывать типы данных, но у данных есть тип, и вы не можете добавить строку с целым числом, но вы можете добавить число с плавающей точкой с целым числом: «компилятор» (который в случае с Javascript является компилятором JIT (Just in Time). Javascript часто называют «интерпретируемым» языком, потому что исторически браузеры интерпретировали код Javascript, но в настоящее время механизмы Javascript являются компиляторами.

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

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

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


Компилятор компилируется, будь то JIT или нет; и интерпретатор интерпретирует без компиляции (потому что если нет, то это будет компилятор!). Это очень разные вещи. А что касается «Java забавного» из-за интерпретации байт-кода, учтите, что даже машинный код 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 может означать что-либо без контекста, но, в частности, может означать изменение буквы на нижний регистр.

CPU 8086 (все еще) имеет специальные инструкции под названием DAA ※, которые используются, когда регистр содержит 2 десятичных цифры, поэтому, если вы просто использовали эту инструкцию, вы интерпретируете ее как две цифры 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.