Типы данных в процессоре
Непосредственные данные, представляющие собой числовые или символьные значения, являющиеся частью команды.
Данные простого типа, описываемые с помощью ограниченного набора директив резервирования памяти, позволяющих выполнить самые элементарные операции по размещению и инициализации числовой и символьной информации. При обработке этих директив сохраняется в таблице символов информация о местоположении данных (значения сегментной составляющей адреса и смещения) и типе данных, то есть единицах памяти, выделяемых для размещения данных в соответствии с директивой резервирования и инициализации данных.
Эти два типа данных являются элементарными, или базовыми; работа с ними поддерживается на уровне системы команд микропроцессора. Используя данные этих типов, можно формализовать и запрограммировать практически любую задачу. Но насколько это будет удобно -- вот вопрос.
Данные сложного типа, которые были введены с целью облегчения разработки программ. Сложные типы данных строятся на основе базовых типов, которые являются как бы кирпичиками для их построения. Введение сложных типов данных позволяет несколько сгладить различия между языками разных уровней. У программиста появляется возможность сочетания преимуществ языка разных уровней (в направлении абстракции данных), что в конечном итоге повышает эффективность конечной программы [3; c.69].
Обработка информации, в общем случае, процесс очень сложный. Это косвенно подтверждает популярность языков высокого уровня. Одно из несомненных достоинств языков высокого уровня -- поддержка развитых структур данных. При их использовании программист освобождается от решения конкретных проблем, связанных с представлением числовых или символьных данных, и получает возможность оперировать информацией, структура которой в большей степени отражает особенности предметной области решаемой задачи. В то же самое время, чем выше уровень такой абстракции данных от конкретного их представления в компьютере, тем большая нагрузка ложится на компилятор с целью создания действительно эффективного кода. Ведь нам уже известно, что в конечном итоге все написанное на языке высокого уровня в компьютере будет представлено на уровне машинных команд, работающих только с базовыми типами данных. Таким образом, самая эффективная программа -- программа, написанная в машинных кодах, но писать сегодня большую программу в машинных кодах -- занятие не имеющее слишком большого смысла.
Понятие простого типа данных носит двойственный характер. С точки зрения размерности (физическая интерпретация), микропроцессор аппаратно поддерживает следующие основные типы данных (рис. 1):
байт -- восемь последовательно расположенных битов, пронумерованных от 0 до 7, при этом бит 0 является самым младшим значащим битом;
слово -- последовательность из двух байт, имеющих последовательные адреса. Размер слова -- 16 бит; биты в слове нумеруются от 0 до 15. Байт, содержащий нулевой бит, называется младшим байтом, а байт, содержащий 15-й бит - старшим байтом. Микропроцессоры имеют важную особенность -- младший байт всегда хранится по меньшему адресу. Адресом слова считается адрес его младшего байта. Адрес старшего байта может быть использован для доступа к старшей половине слова.
двойное слово -- последовательность из четырех байт (32 бита), расположенных по последовательным адресам. Нумерация этих бит производится от 0 до 31. Слово, содержащее нулевой бит, называется младшим словом, а слово, содержащее 31-й бит, - старшим словом. Младшее слово хранится по меньшему адресу. Адресом двойного слова считается адрес его младшего слова. Адрес старшего слова может быть использован для доступа к старшей половине двойного слова.
учетверенное слово -- последовательность из восьми байт (64 бита), расположенных по последовательным адресам. Нумерация бит производится от 0 до 63. Двойное слово, содержащее нулевой бит, называется младшим двойным словом, а двойное слово, содержащее 63-й бит, -- старшим двойным словом. Младшее двойное слово хранится по меньшему адресу. Адресом учетверенного слова считается адрес его младшего двойного слова. Адрес старшего двойного слова может быть использован для доступа к старшей половине учетверенного слова [1; c.105].
Рис. 1. Основные типы данных микропроцессора
Кроме трактовки типов данных с точки зрения их разрядности, микропроцессор на уровне команд поддерживает логическую интерпретацию этих типов (рис. 2):
Целый тип со знаком -- двоичное значение со знаком, размером 8, 16 или 32 бита. Знак в этом двоичном числе содержится в 7, 15 или 31-м бите соответственно. Ноль в этих битах в операндах соответствует положительному числу, а единица -- отрицательному. Отрицательные числа представляются в дополнительном коде. Числовые диапазоны для этого типа данных следующие:
Рис. 2. Основные логические типы данных микропроцессора
Целый тип без знака -- двоичное значение без знака, размером 8, 16 или 32 бита. Числовой диапазон для этого типа следующий:
байт -- от 0 до 255;
слово -- от 0 до 65 535;
двойное слово -- от 0 до 232-1.
Указатель на память двух типов:
ближнего типа -- 32-разрядный логический адрес, представляющий собой относительное смещение в байтах от начала сегмента. Эти указатели могут также использоваться в сплошной (плоской) модели памяти, где сегментные составляющие одинаковы;
Цепочка -- представляющая собой некоторый непрерывный набор байтов, слов или двойных слов максимальной длины до 4 Гбайт.
Битовое поле представляет собой непрерывную последовательность бит, в которой каждый бит является независимым и может рассматриваться как отдельная переменная. Битовое поле может начинаться с любого бита любого байта и содержать до 32 бит.
Неупакованный двоично-десятичный тип -- байтовое представление десятичной цифры от 0 до 9. Неупакованные десятичные числа хранятся как байтовые значения без знака по одной цифре в каждом байте. Значение цифры определяется младшим полубайтом [5; c.33].
Упакованный двоично-десятичный тип представляет собой упакованное представление двух десятичных цифр от 0 до 9 в одном байте. Каждая цифра хранится в своем полубайте. Цифра в старшем полубайте (биты 4-7) является старшей.
Фундаментальные типы данных
Фундаментальными типами для архитектуры IA-32 являются:
байт (byte) | - | 8 бит |
слово (word) | - | 16 бит |
двойное слово (doubleword) | - | 32 бит |
четверное слово (quadword) | - | 64 бит |
При размещении данных в памяти рекомендуется использовать выравнивание, т.е. слова следует размещать по четным адресам, двойные слова - по адресам, кратным четырем, и т.п. Обращение к невыравненным данным вынуждает процессор делать дополнительный цикл чтения или записи. Так, чтение двойного слова AA5A3F12h по адресу 1238h возможно за один цикл шины, тогда как чтение числа 3F12008Ch по адресу 1236h потребует как минимум двух циклов шины.
Языки высокого уровня обеспечивают выравнивание на уровне компилятора (для всей программы или для всего модуля). Ассемблер предоставляет директиву ALIGN, с помощью которой можно определять выравнивание различных участков данных.
Целые типы данных
Процессор, оперируя перечисленными фундаментальными типами данных, позволяет в программе интерпретировать эти значения как целочисленные. Целое число может считаться знаковым или беззнаковым. Большинство арифметических инструкций процессора работают одинаково для знаковых и для беззнаковых чисел, однако для некоторых инструкций (инструкции условных переходов, деление, умножение) существуют модификации для работы со знаковыми и беззнаковыми целыми числами.
Фундаментальный тип кодирует беззнаковое число, если его значение интерпретируется как целое число от 0 до 2 n -1, где n - разрядность типа. Для чисел со знаком используется комплементарное кодирование (дополнение до 1): т.е. отрицательному числу, модуль которого M, соответствует код NOT(M)+1, где NOT - операция побитового инвертирования. При этом по старшему разряду кода можно определить знак числа: 0 - неотрицательное число, 1 - отрицательное число. Знаковым числам соответствует диапазон -2 n/2 . +2 n/2 -1.
Фундаментальный тип | Целый тип | Диапазон |
---|---|---|
байт (byte) | символ со знаком (signed char) | -128. +127 |
символ без знака (unsigned char) | 0. 255 | |
слово (word) | короткое со знаком (signed short) | -32768. +32767 |
короткое без знака (unsigned short) | 0. 65535 | |
двойное слово (doubleword) | целое со знаком (signed int) | -2147483648. +2147483647 |
целое без знака (unsigned int) | 0. 4294967295 |
Вещественные типы данных
Встроенный математический сопроцессор (FPU) микропроцессоров IA-32 позволяет оперировать с вещественными типами данных. Вещественные числа кодируются в соответствии со стандартом IEEE-754. Старший разряд двоичного представления вещественного числа всегда кодирует знак числа. Остальная часть разбивается на две части: экспонента и мантисса. Вещественное число вычисляется как: (-1) S *2 E *M, где S - знаковый бит числа, E - экспонента, M - мантисса. Обычно процессор оперирует с нормализованными вещественными числами, у которых 1
(single precision) - 32 бит
(double precision) - 64 бит
(extended precision) - 80 бит
Ближний указатель представляет собой 32-битное смещение (эффективный адрес) от начала сегмента. Ближние указатели используются в сплошной модели памяти, а также в сегментированной модели, если селектор сегмента задан неявно.
Дальний указатель (логический адрес) состоит из 16-битного селектора сегмента и 32-битного смещения (эффективного адреса). Дальние указатели используются в сегментированной модели памяти, когда требуется явное задание селектора сегмента.
В 16-битном режиме адресации смещения имеют размер 16 бит, поэтому размер ближнего адреса составляет 16 бит, а дальнего - 32 бита.
Битовое поле - непрерывная последовательность битов, в которой каждый бит рассматривается как независимая переменная. Оно может начинаться с любого бита любого байта и может быть длиной до 32 бит.
Строка - непрерывная последовательность битов, байтов, слов или двойных слов. Битовая строка может начинаться с любой позиции любого байта и содержать до 2 32 -1 битов. Строка байтов может содержать байты, слова или двойные слова и иметь размер до 2 32 -1 байт.
Двоично-десятичные числа
Каждый из представленных на рис. 2.2 типов данных может начинаться с любого адреса: это означает, что слово не обязано начинаться с чётного адреса; двойное слово – с адреса, кратного 4 и т.д. Таким образом достигается максимальная гибкость структур данных и эффективность использования памяти.
На базе основных типов данных строятся все остальные типы, распознаваемые командами процессора.
Целочисленные данные
Четыре формата данных (байт, слово, двойное слово, учетверенное слово) с фиксированной точкой могут быть как со знаком, так и без знака. Под знак отводится старший бит формата данных. Представление таких данных и выполнение операций в арифметико-логическом устройстве (ALU) производится в дополнительном коде.
Адрес N+15
младшее двойное слово
старшее двойное слово
младшее квадро слово
старшее квадро слово
7
Рис. 2.2. Основные типы данных
Данные в формате с плавающей точкой х87
Формат включает три поля: Знак (S), Порядок и Мантисса (рис. 2.3). Поле мантиссы содержит значащие биты числа, а поле порядка содержит степень 2 и определяет масштабирующий множитель для мантиссы. Форматы данных поддерживаются блоком обработки чисел с плавающей точкой (FPU).
Рис. 2.3. Форматы данных с плавающей точкой
Двоично-десятичные данные (BCD)
На рис. 2.4 приведены форматы двоично-десятичных данных.
Рис. 2.4. Форматы двоично-десятичных данных
Данные типа строка
Строка представляет собой непрерывную последовательность бит, байт, слов или двойных слов (рис. 2.5). Строка бит может быть длиной до 1 Гбита, а длина остальных строк может составлять от 1 байта до 4 Гбайтов. Поддерживается АLU.
Рис. 2.5. Данные типа строка
Символьные данные
Поддерживаются строки символов в коде ASCII и арифметические операции (сложение, умножение) над ними (рис. 2.6). Поддержка осуществляется блоком АLU.
Указатель содержит величину, которая определяет адрес фрагмента данных. Поддерживается два типа указателей, приведенных на рис. 2.7.
Целочисленные данные могут быть как со знаком, так и без знака (рис. 2.8).
Упакованные 2 двойных слова
Упакованные 4 слова
Упакованные 8 байт
Рис. 2.8. Данные ММХ-технологии
Данные SSE-расширения
Рис. 2.9. Данные SSE-расширения
Данные расширения SSE2
Рис. 2.10. Данные SSE2 расширения с плавающей запятой
На рис. 2.11 показаны 4 формата упакованных в 128 бит целочисленных данных, которые могут быть как со знаком, так и без знака.
Упакованные 2 64-разрядных слова
Упакованные 4 двойных слова
Упакованные 8 слов
Упакованные 16 байт
0
Рис. 2.11. Целочисленные данные SSE2 расширения
Данные в IA-64
В IA-64 непосредственно поддерживается 6 типов данных, в том числе три формата, используемых ранее (одинарная точность, двойная точность, расширенная точность), 82-разрядный формат данных с плавающей точкой (рис. 2.12) и 64-разрядные целые – со знаком и без знака.
62. СТРУКТУРА И ФОРМАТЫ КОМАНД ЭВМ
Команда представляет собой код, определяющий операцию и данные, участвующие в операции.
По характеру выполняемых операций различают следующие основные группы команд:
а) команды арифметических операций над числами с фиксированной и плавающей точками;
б) команды десятичной арифметики;
в) команды логических операций и сдвигов;
г) команды передачи кодов;
д) команды операций ввода/вывода;
е) команды передачи управления;
ж) команды векторной обработки;
з) команды задания режима работы машины и др.
Команда в общем случае состоит из операционной и адресной частей (рис. 2.14, а).
В свою очередь, эти части, что особенно характерно для адресной части, могут состоять из нескольких полей.
Операционная часть содержит код операции (КОП), который задает вид операции (сложение, умножение и др.). Адресная часть содержит информацию об адресах операндов и результате операции.
Структура команды определяется составом, назначением и расположением полей в команде.
Форматом команды называют ее структуру с разметкой номеров разрядов (бит), определяющих границы отдельных полей команды, или с указанием числа бит в определенных полях.
Важной и сложной проблемой при проектировании ЭВМ является выбор структуры и форматов команды, т.е. ее длины, назначения и размерности отдельных ее полей. Естественно стремление разместить в команде в возможно более полной форме информацию о предписываемой командой операции. Однако в условиях, когда в современных ЭВМ значительно возросло число выполняемых различных операций и соответственно команд (в системе команд х86 более 500 команд) и значительно увеличилась емкость адресуемой основной памяти (4 Гбайт, 6 Гбайт), это приводит к недопустимо большой длине формата команды.
Действительно, число двоичных разрядов, отводимых под код операции, должно быть таким, чтобы можно было представить все выполняемые машинные операции. Если ЭВМ выполняет М различных операций, то число разрядов в коде операции
nкоп і log2 М; например, при М = 500 nкоп = 9.
Если основная память содержит S адресуемых ячеек (байт), то для явного представления только одного адреса необходимо в команде иметь адресное поле для одного операнда с числом разрядов
nА і log2 S; например, при S = 4 Гбайт nА = 32.
Отмечавшиеся ранее, характерные для процесса развития ЭВМ расширение системы (наборы) команд и увеличение емкости основной памяти, а особенно создание микроЭВМ с коротким словом, потребовали разработки методов сокращения длины команды. При решении этой проблемы существенно видоизменилась структура команды, получили развитие различные способы адресации информации.
Проследим изменения классических структур команд.
Чтобы команда содержала в явном виде всю необходимую информацию о задаваемой операции, она должна, как это показано на рис. 2.14, б, содержать следующую информацию:
А1, А2 – адреса операндов, А3 – адрес результата, А4 – адрес следующей команды (принудительная адресация команд).
Такая структура приводит к большой длине команды (например, при М = 500, S = 4 Гб длина команды – 137 бит) и неприемлема для прямой адресации операндов основной памяти. В компьютерах с RISC-архитектурой четырехадресные команды используются для адресации операндов, хранящихся в регистровой памяти процессора.
Можно установить, что после выполнения данной команды, расположенной по адресу К (и занимающей L ячеек), выполняется команда из (К + L)-й ячейки. Такой порядок выборки команды называется естественным. Он нарушается только специальными командами передачи управления. В таком случае отпадает необходимость указывать в команде в явном виде адрес следующей команды.
В трехадресной команде (рис. 2.14, в) первый и второй адреса указывают ячейки памяти, в которых расположены операнды, а третий определяет ячейку, в которую помещается результат операции.
Можно условиться, что результат операции всегда помещается на место одного из операндов, например первого. Получим двухадресную команду (рис. 2.14, г), т.е. для результата используется подразумеваемый адрес.
В одноадресной команде (рис. 2.14, д) подразумеваемые адреса имеют уже и результат операции, и один из операндов. Один из операндов указывается адресом в команде, в качестве второго используется содержимое регистра процессора, называемого в этом случае регистром результата, или аккумулятором. Результат операции записывается в тот же регистр.
Наконец, в некоторых случаях возможно использование безадресных команд (рис. 2.14, е), когда подразумеваются адреса обоих операндов и результата операции, например при работе со стековой памятью.
в
Следует различать понятия адресный код в команде АR и исполнительный (физический адрес) адрес АИ.
Адресный код — это информация об адресе операнда, содержащаяся в команде.
Исполнительный адрес — это номер ячейки памяти, к которой производится фактическое обращение.
Таким образом, способ адресации можно определить как способ формирования исполнительного адреса операнда АИ.по адресному коду команды АК.
В системах команд современных ЭВМ часто предусматривается возможность использования нескольких способов адресации операндов для одной и той же операции. Для указания способа адресации в некоторых системах команд выделяется специальное поле в команде — поле «метод» (указатель адресации УА), рис.2.3, а.
В этом случае любая операция может выполняться с любым способом адресации, что значительно упрощает программирование.
явная адресация
неявная адресация.
При неявной адресации адресное поле в команде отсутствует, адрес операнда подразумевается кодом операции.
Классификация способов адресации по кратности обращения в память.
Широко используются следующие методы адресации операнда с различной кратностью обращения (r) в память:
1. Непосредственная (r = 0)
3. Косвенная (r і 2)
Непосредственная адресация операнда.
Обращение к регистровой памяти (РП) или ОП не производится (R = 0). Таким образом уменьшается время выполнения операции, сокращается объем памяти.
Прямая адресация операндов.
При этом способе (рис.2.5) адресации обращение за операндом в РП или ОП производится по адресному коду в поле команды, т.е. исполнительный адрес операнда совпадает с адресным кодом команды (АИСП. = АК). Обеспечивая простоту программирования, этот метод имеет существенные недостатки, так как для адресации к ячейкам памяти большой емкости требуется «длинное» адресное поле в команде.
Косвенная адресация операндов.
Адресный код команды указывает адрес ячейки памяти, в которой находится не сам операнд, а лишь адрес операнда, называемый указателем операнда. Адресация к операнду через цепочку указателей (косвенных адресов) называется косвенной.
Адрес указателя - остается неизменным, а косвенный адрес может изменяться в процессе выполнения программы. Это обеспечив переадресацию данных, т.е. упрощает обработку массивов и списковых структур данных, упрощает передачу параметров подпрограммам, но не обеспеч перемещаемость программ в памяти. (рис. 2.6 а)
64. ПРИНЦИПЫ ОРГАНИЗАЦИИ СИСТЕМЫ ПРЕРЫВАНИЯ ПРОГРАММ
Для оценки эффективности систем прерывания могут быть использованы следующие характеристики.1. Общее число запросов прерывания (входов в систему прерывания).
2. Время реакции — время между появлением запроса прерывания и моментом прерывания текущей программы.
Для одного и того же запроса задержки в исполнении прерывающей программы зависят от того, сколько программ со старшим приоритетом ждут обслуживания, поэтому время реакции определяют для запроса с наивысшим приоритетом (tP).
Время реакции зависит от того, в какой момент допустимо прерывание. Большей частью прерывание допускается после окончания текущей команды. В этом случае время реакции определяется в основном длительностью выполнения команды
Это время реакции может оказаться недопустимо большим для ЭВМ, предназначенных для работы в реальном масштабе времени. В таких машинах часто допускается прерывание после любого такта выполнения команды (микрокоманды). Однако при этом возрастает количество информации, подлежащей запоминанию и восстановлению при переключении программ, так как в этом случае необходимо сохранять также и состояние счетчика тактов, регистра кода операции и некоторых других узлов. Такая организация прерывания возможна только в машинах с быстродействующей сверхоперативной памятью.
Рис.3.15. Упрощенная временная диаграмма процесса прерывания
Имеются ситуации, в которых желательно немедленное прерывание. Если аппаратура контроля обнаружила ошибку, то целесообразно сразу же прервать операцию, пока ошибка не оказала влияние на следующие такты работы программы.
3. Затраты времени на переключение программ (издержки прерывания) равны суммарному расходу времени на запоминание и восстановление состояния программы
Регистровые структуры центрального процессора IA-32.
регистры общего назначения;
регистры сегментации;
регистр флагов;
регистры управления;
регистры системного адреса;
регистр тестов;
регистр отладки.
Регистры базовой архитектуры микропроцессора включают:
A)регистры общего адреса и данных Б)указатель команд В)регистр флагов.
Данные регистры при включении новой задачи загружаются новым содержимым. Базовая архитектура содержит 6 прямо доступных сегмента, каждый размером до 4 Гбайт. Сегменты указываются значениями селектора, помещенными в регистр сегмента.
Регистры отладки и тестовые регистры
Регистры общего назначения (РОН)
Указатель команд (IP)
Регистр флагов
Сегментные регистры
Регистры дескриптора сегмента
Управляющие регистры
Регистры системного адреса
Регистры IA-64
В состав регистровых файлов IA-64 входят: 128 регистров общего назначения GPR (64-разрядных); 128 регистров с плавающей запятой FR (82-разрядных); 128 прикладных регистров (в основном 64-разрядных) AR; 64 одноразрядных регистров предикатов PR; 8 регистров переходов BR(64-разрядных);не менее 4-х регистров идентификатора процесса CPUID; счетчик команд IP; регистр маркера текущего окна CFM стека регистров и др.
Регистры CPUID являются 64-разрядными. В CPUID-регистрах 0 и 1 лежит информация о производителе, в регистре 2 находится серийный номер процессора, а в регистре 3 задается тип процессора (семейство, модель, версия архитектуры и т.п.) и число CPUID-регистров. Разряды регистра 4 указывают на поддержку конкретных особенностей IA-64, т.е. тех, которые реализованы в данном процессоре.
Среди других прикладных регистров укажем на AR16 (RSC) - регистр конфигурации стека регистров, используемый для управления работой "машиной" стека регистров IA-64 (RSE); AR17 (BSP), в котором находится адрес в памяти, где сохраняется положение GR32 в текущем окне стека; AR40 (FPSR) - регистр состояния для команд с плавающей запятой IA-64; AR44 (ITC) - интервальный таймер; AR64 (PFS) - регистр предыдущего состояния функции, куда автоматически копируются некоторые другие регистры при вызове подпрограмм; AR65 (LC), используемый для организации циклов со счетчиком, и, наконец, 6-разрядный регистр эпилога AR66 (EC). Ряд AR-регистров является фактически регистрами IA-32 (дескриптор сегмента кодов, дескриптор сегмента стека)
GR0-31 называются статическими регистрами (GR0 всегда содержит 0), а GR32-127 - стекируемыми регистрами. Статические регистры "видны" всем программам. Стекируемые регистры становятся доступными в программной единице через окно стека регистров, включающее локальные и выходные регистры, число которых задается командой alloc.
Вращение регистров является в некотором роде частным случаем переименования регистров, применяемого во многих современных суперскалярных процессоров с внеочередным спекулятивным выполнением команд. В отличие от них, вращение регистров в IA-64 управляется программно.
64-разрядные регистры переходов BR0-7 применяются для указания адреса перехода в соответствующих командах перехода (если адрес перехода не кодируется в команде явно). Регистры предикатов PR0-63 являются одноразрядными; в них помещаются результаты команд сравнения. Обычно эти команды устанавливают сразу два регистра PR в зависимости от условия - соответственно истинность условия и его отрицания. Такая избыточность обеспечивает дополнительную гибкость.
Регистры х86-64
В процессорах x86-64 архитектуры (Hammer, Athlon 64, Opteron) существующие в х86 регистры общего назначения (GPR) расширены с 32 до 64 бит (см. рис. 3.7) и к ним добавлены еще 8 новых 64-разрядных регистров (R8 – 15). Также 8 новых регистров (XMM8 – 15) добавлено в блок SSE, что обесп
ечивает поддержку SSE-2.
В блоке FPU используются существующие в х87 регистры данных (80-разрядные).
Регистр указателя команд (EIP) также расширен до 64 разрядов.
Регистровые расширения - это один из самых больших шагов в развитии архитектуры, пару десятков лет просуществовавшей на восьми регистрах общего назначения. Новый REX-префикс делает доступными 8 новых регистров общего назначения (R8 - R15) и 8 новых регистров SSE (XMM8 - XMM15), а также расширения всех РОН до 64 бит.
Без префикса REX размер операнда по умолчанию для большинства команд - 32 бит. Это даёт доступ к регистрам EAX, EBX, ECX, EDX, EDI, ESI, EBP и ESP. Исключение составляют две группы команд, которые будут рассмотрены ниже. Чтобы получить доступ к полному 64-битному операнду (RAX, RBX, RCX, RDX, RDI, RSI, RBP, RSP) и новым регистрам R8 - R15, команда должна содержать префикс REX.
Для кодирования префикса REX использованы коды 40h - 4Fh 2 . Эти коды трактуются в 32-битном режиме как однобайтные инструкции INC (40h - 47h) и DEC (48h - 4Fh) над 32-разрядными регистрами EAX - ESP.
Подмостки — отечество актера, и нужно все время продлевать паспорт, чтобы не лишиться гражданства. Чарлтон Хестон
ещё >>
Аннотация: В данной лекции Вы познакомитесь с основными типами "машинных данных" и допустимыми операциями над ними. Вы также узнаете разницу между "машинными" и "пользовательскими" типами данных.
"Программа = Алгоритм + Структура данных"
Цель лекции:
- Познакомиться с основными типами данных и научиться использовать их.
- Познакомиться с операциями над типами данных.
- Изучить особенности каждого типа данных.
Как уже указывалось в эпиграфе, в этой лекции будет подробно рассказано о типах данных - константах, переменных и т.п., используемых при программировании на любом языке. Правильно выбранный тип данных влияет не только на реализацию тех или иных алгоритмов - от него также зависит эффективность реализации алгоритма, скорость вычислений, размер программы, точность расчетов и т.п.
Следует отметить, что концепция типов данных не реализована в таких языках, как Perl, Visual Basic Script ( VBScript ), не полностью реализована в Quick Basic , Visual Basic и т.п. Именно поэтому не рекомендуется использовать эти языки для начинающих изучать программирование .
Типы данных в таких языках, как C, C++, Java можно принудительно приводить к определенному типу. В этих языках автор советует так и поступать - если потребуется, применять принудительное приведение типов , а не ограничиваться приведением по-умолчанию. В противном случае могут возникнуть ошибки, например: "Не могу привести тип ' unsigned char *' в 'const char *'".
5.1. Примитивные (машинные) типы данных
Как уже говорилось выше, почти во всех языках программирования выделяются "машинные" типы данных. Вкратце объясним их происхождение.
Как известно из школьных учебников по информатике [36, 54, 53, 35], любое число, любые символы, любые объекты в памяти ЭВМ представляются в виде последовательности нулей и единиц - битов. Бит (от английского Binary digIT ) является единицей информации, принимающей одно из двух значений: "0" и "1". Поскольку бит - очень малая величина, информацию обычно выражают в байтах или кратных ему числе битов. Один байт соответствует восьми битам. Иначе говоря, в одном байте можно закодировать 256 (2^8) символов, представить целые числа без знака от 0 до 255, или представить целые числа со знаком от -128 до +127. Заметим, что все символы в компьютере представлены в виде целых чисел без знака.
Отступление. В середине 70-х годов XX века ученые подсчитали, что человеческий мозг вмещает в себя ~10^18 бит информации. Это число соответствовало в то время всей информации, содержащейся в библиотеке им. В.И. Ленина. В переводе на современный компьютерный язык это соответствует приблизительно одному экзабайту - миллиону гигабайт информации, что приближенно равно объему одной крупной распределенной базы данных бронирования авиабилетов и авиаперевозок (по оценкам автора). Почему же возможности мозга человека превышают возможности "компьютерного" интеллекта? Дело в том, что человеческий мозг может удерживать в своей памяти, по аналогии с кошельком, как "медные монеты" - необработанные записи, последовательности букв и цифр, так и "золотые монеты" - сложные, обработанные данные, в виде готовых концепций, теорем и т.д. Это делает мозг более "гибкой" системой, чем компьютер (позволяя, путем "сжатия с потерями" уменьшать объем информации в 100 и более раз).
Итак, все данные в ЭВМ представляются в виде одного или нескольких битов. Тогда напрашивается вопрос: "А откуда в языках программирования такое большое число машинных типов данных, если все кодируется битами?" Автор отвечает: количество машинных типов данных определяется количеством регистров и их типом в центральном процессоре ЭВМ. Регистр можно представить как "сверхоперативную", быструю, встроенную в центральный процессор память . Эти регистры имеют длину 1 байт , 2 байта ("полуслово", " слово "), 4 байта (" слово ", "двойное слово ") и 8 байт ("двойное слово "). Изредка используются и более длинные регистры (например, для хранения [чисел с плавающей точкой] повышенной разрядности).
Помимо своего размера (так называемой разрядности) регистров различают также назначение регистра и формат хранимых в нем данных. Подробнее о машинных типах данных смотри этот раздел ниже.
5.2. Целые числа и целочисленная арифметика
5.2.1. Целый тип
Наиболее простыми в реализации и "очевидными" с точки зрения " здравого смысла " являются целочисленные типы данных. Они представляют собой запись чисел в "двоичном" формате, в виде последовательности нулей и единиц. Различают два вида целых чисел: "целые без знака" и "целые со знаком".
Тип данных "целые без знака" представляют собой натуральный ряд чисел, которые начинаются с "0" (а не с "1", как в математике!) и продолжаются вплоть до исчерпания разрядности регистра.
Тип данных "целые со знаком" содержат в старшем бите (по-другому - в самом "левом", первом по порядку бите) признак знака. Если этот бит имеет значение: "0", то число считается положительным, если "1" - отрицательным числом.
Примечание: отрицательные числа представляют в ЭВМ в виде дополнительного кода . Подробнее о дополнительном коде смотри, например, [62], а также школьные учебники по информатике [35, 36, 53, 54].
В таблице 5.1 представлены максимальное (max) и минимальное (min) значения, применяемые числами в целочисленных регистрах различной разрядности для типов "целые со знаком" и "целые без знака". Между этими максимальными и минимальными значениями могут принимать целочисленные значения константы и переменные указанных типов.
В таблице 5.2 дается соответствие между разрядностями целочисленных регистров и связанными с ними обозначениями типов на языках Quick Basic, C/C++, Java. В этой же таблице приведены "псевдонимы" "машинных" типов данных, применяемых в библиотеке Windows API. Подробнее о Windows API смотри в книгах 90.
5.2.2. Целочисленная арифметика
С целочисленными типами данных возможны следующие операции:
- сложение;
- вычитание;
- умножение;
- целочисленное деление;
- нахождение остатка от деления;
- смена знака числа;
- инкремент числа;
- декремент числа;
- а также все операции отношения .
Все эти операции, их обозначения, действия, а также приоритеты операций и комментарии к ним смотри таблицу 5.3.
5.2.3. Особые ситуации при работе с целыми числами
Целочисленная арифметика генерирует следующие ошибки [39,40], вызывает так называемые программные прерывания :
- деление на ноль ( divide by zero);
- переполнение ( overflow ) - попытка записать в регистр целое число с разрядностью, превышающей разрядность регистра, например: short i = 2000000 или unsigned short u=-1;
- исчезновение знака - прерывание, указывающее, что в старший бит регистра (то есть в признак знака) был перенос единицы из следующего за ним разряда (бита). Соответствует прерыванию "переполнение", но для целых чисел со знаком.
5.2.4. Замечания о целочисленном делении
Замечание по целочисленному делению. Целочисленное деление отличается от "обычного математического" деления в том, что при целочисленном делении происходит "отбрасывание" дробной части результата, например:
- 2/3 = 0;
- 3/3 = 1;
- 4/3 = 1;
- 5/3 = 1;
- 6/3 = 2;
- и т.д.
На практике это приводит к большим ошибкам округления при расчетах. Но иногда следует использовать только целочисленную арифметику. Например, при выдаче информации на экран дисплея в "графическом" виде по-умолчанию используется (во всяком случае, в библиотеке Windows API) только целочисленные значения. Для этих целей использование целочисленной арифметики - "естественно".
- use integer - для включения целочисленной арифметики;
- no integer - для выключения целочисленной арифметики.
5.3. Булевы типы. Булева алгебра
5.3.1. Булева алгебра: введение
Булева алгебра - это раздел математики, изучающий операции с логическими данными, то есть данными, принимающие значения: "Истина" и "Ложь" (по-английски: "true" и "false"). Эта дисциплина была разработана английским математиком XIX века Джорджем Булем, имя которого она носит.
К булевым операциям (которые в русскоязычной литературе чаще называют логическими операциями) относятся:
- конъюнкция (логическое "И");
- дизъюнкция (логическое "ИЛИ");
- отрицание (логическое "НЕ");
- логическое " исключающее ИЛИ ";
- логическая "эквивалентность";
- логическое "следствие".
Из этих логических операций первые три операции присутствуют практически во всех языках программирования, а последние две - только в языках логического программирования (и то не во всех). При этом операция логического "НЕ" - унарная операция , применимая к следующей за ней переменной, а остальные операции - бинарные (применимые к паре значений: предыдущему и последующему). Результаты логических операций представлены [в таблице 5.4]. В ней же представлены обозначения этих операций в математике, языках Quick Basic, C/C++, Java.
5.3.2. Булевы типы
Как уже сказано выше, логические выражения могут принимать только два значения: "false" (ложь) и "true" (истина). Эти значения-константы определены следующим образом:
Логично использовать для этих констант целое число разрядностью 1 бит, но. Поскольку минимальным размером регистра, отводимого под целое число, является 1 байт, то именно ячейка памяти этого размера служит для хранения числа с типом данных: "Boolean". На самом деле размер этого типа данных может составлять 2 или даже 4 байта. Это связано со следующими обстоятельствами.
В основном стандарте для языка Си: ANSI C, - отсутствует булевский тип данных. Вместо него используется целый тип данных: integer (int). Этот тип данных реализован в различных компиляторах по-разному, и занимает от 2-х до 4-х байтов. Константе "ложь" ("FALSE") соответствует значение; "0", а любое ненулевое значение воспринимается как "истина". Это позволяет написать на языке Си компактный код, например:
Описывает цикл "Пока", завершающийся при достижении конца файла, связанного с потоком stream. Информацию по потокам и окончанию файлов смотрите в следующих лекциях.
Не смотря на несоответствие стандарту ANSI C, в стандартной библиотеке Windows API для языков Си/Си плюс-плюс введен тип BOOL, являющегося реализацией булевского типа данных. Тип данных: "Boolean" также введен в стандартах на C++ и Java.
Булевский тип данных отсутствует в Quick Basic и более старых реализациях языка Basic, но присутствует в языке Visual Basic и его "клонах".
Примечание: при вычислении булевских выражений часто не требуется принудительно приводить значения логических выражений логической переменной .
Аннотация: В лекции рассматриваются понятие типов данных в языках программирования, приводится классификация типов данных в С++, излагаются особенности представления базовых типов и операций над ними, рекомендации и правила выполнения операции преобразования базовых типов в С++.
Цель лекции: изучить классификацию типов и их внутреннее представление в языке С++, научиться работать со стандартными и пользовательскими типами .
Основная цель любой программы состоит в обработке каких-либо данных, например, чисел или текстов. Данные могут быть различного вида или типа и, в зависимости от этого, с ними можно выполнять разные действия.
В любом языке программирования каждая константа, переменная , результат вычисления выражения или функции должны иметь определенный тип данных .
Тип данных – это множество допустимых значений, которые может принимать тот или иной объект , а также множество допустимых операций, которые применимы к нему. В современном понимании тип также зависит от внутреннего представления информации.
Таким образом, данные различных типов хранятся и обрабатываются по-разному. Тип данных определяет:
- внутреннее представление данных в памяти компьютера;
- объем памяти, выделяемый под данные;
- множество (диапазон) значений, которые могут принимать величины этого типа;
- операции и функции, которые можно применять к данным этого типа.
Исходя из данных характеристик, необходимо определять тип каждой величины, используемой в программе для представления объектов. Обязательное описание типа позволяет компилятору производить проверку допустимости различных конструкций программы. От выбора типа величины зависит последовательность машинных команд, построенная компилятором.
Классификация типов данных в С++
Современные языки программирования, как правило, могут иметь набор простых типов, являющихся встроенными в данный язык программирования , и средства для создания производных типов.
Объектно-ориентированные языки программирования позволяют определять типы класса.
Реализация простых типов данных заключается в способе представления значений данного типа в компьютере и в наборе операций, поддерживаемых для данного типа.
Тип данных определяет размер памяти, выделяемой под переменную данного типа при ее создании. Язык программирования C++ поддерживает следующие типы данных (рис. 1.1).
- Базовые типы. Базовые типы предопределены стандартом языка , указываются зарезервированными ключевыми словами и характеризуются одним значением. Их не надо определять и их нельзя разложить на более простые составляющие без потери сущности данных. Базовые типы объектов создают основу для построения более сложных типов .
- Производные типы. Производные типы задаются пользователем, и переменные этих типов создаются как с использованием базовых типов, так и типов классов.
- Типы класса. Экземпляры этих типов называются объектами.
Существует четыре спецификатора типа данных, уточняющих внутреннее представление и диапазон базовых типов:
Рассмотрим более подробно базовые типы данных .
Целочисленный (целый) тип данных (тип int)
Переменные данного типа применяются для хранения целых чисел ( integer ). Описание переменной , имеющей тип int , сообщает компилятору, что он должен связать с идентификатором (именем) переменной количество памяти, достаточное для хранения целого числа во время выполнения программы.
Границы диапазона целых чисел, которые можно хранить в переменных типа int , зависят от конкретного компьютера, компилятора и операционной системы (от реализации). Для 16-разрядного процессора под него отводится 2 байта, для 32-разрядного – 4 байта.
Для внутреннего представления знаковых целых чисел характерно определение знака по старшему биту (0 – для положительных, 1 – для отрицательных). Поэтому число 0 во внутреннем представлении относится к положительным значениям. Следовательно, наблюдается асимметрия границ целых промежутков.
В целочисленных типах для всех значений определены следующий и предыдущий элементы. Для максимального следующим значением будет являться минимальное в этом же типе, предыдущее для минимального определяется как максимальное значение . То есть целочисленный диапазон условно можно представить сомкнутым в кольцо. Поэтому определены операции декремента для минимального и инкремента для максимального значений в целых типах .
От количества отводимой под объект памяти зависит множество допустимых значений, которые может принимать объект :
- short int – занимает 2 байта, следовательно, имеет диапазон от –32 768 до +32 767;
- int – занимает 4 байта, следовательно, имеет диапазон от –2 147 483 648 до +2 147 483 647;
- long int – занимает 4 байта, следовательно, имеет диапазон от –2 147 483 648 до +2 147 483 647;
- long long int – занимает 8 байтов, следовательно, имеет диапазон от –9 223 372 036 854 775 808 до +9 223 372 036 854 775 807.
Модификаторы signed и unsigned также влияют на множество допустимых значений, которые может принимать объект :
- unsigned short int – занимает 2 байта, следовательно, имеет диапазон от 0 до 65 535;
- unsigned int – занимает 4 байта, следовательно, имеет диапазон от 0 до 4 294 967 295;
- unsigned long int – занимает 4 байта, следовательно, имеет диапазон от 0 до 4 294 967 295;
- unsigned long long int – занимает 8 байтов, следовательно, имеет диапазон от 0 до 18 446 744 073 709 551 615.
Приведем несколько правил, касающихся записи целочисленных значений в исходном тексте программ.
- Нельзя пользоваться десятичной точкой. Значения 26 и 26.0 одинаковы, но 26.0 не является значением типа int .
- Нельзя пользоваться запятыми в качестве разделителей тысяч. Например, число 23,897 следует записывать как 23897.
- Целые значения не должны начинаться с незначащего нуля. Он применяется для обозначения восьмеричных или шестнадцатеричных чисел, так что компилятор будет рассматривать значение 011 как число 9 в восьмеричной системе счисления .
На практике рекомендуется использовать основной целый тип , то есть тип int . Данные основного целого типа практически всегда обрабатываются быстрее, чем данные других целых типов. Короткий тип short подойдет для хранения больших массивов чисел с целью экономии памяти при условии, что значения элементов не выходят за предельные границы для этих типов. Длинные типы необходимы в ситуации, когда не достаточно типа int .
Вещественный (данные с плавающей точкой) тип данных (типы float и double)
Для хранения вещественных чисел применяются типы данных float (с одинарной точностью) и double (с двойной точностью). Смысл знаков "+" и "-" для вещественных типов совпадает с целыми. Последние незначащие нули справа от десятичной точки игнорируются. Поэтому варианты записи +523.5, 523.5 и 523.500 представляют одно и то же значение .
Для представления вещественных чисел используются два формата:
В большинстве случаев используется тип double , он обеспечивает более высокую точность , чем тип float . Максимальную точность и наибольший диапазон чисел достигается с помощью типа long double .
Величина с модификатором типа float занимает 4 байта. Из них 1 бит отводится для знака, 8 бит для избыточной экспоненты и 23 бита для мантиссы . Отметим, что старший бит мантиссы всегда равен 1, поэтому он не заполняется, в связи с этим диапазон модулей значений переменной с плавающей точкой приблизительно равен от 3.14E–38 до 3.14E+38.
Величина типа double занимает 8 байтов в памяти. Ее формат аналогичен формату float . Биты памяти распределяются следующим образом: 1 бит для знака, 11 бит для экспоненты и 52 бита для мантиссы . С учетом опущенного старшего бита мантиссы диапазон модулей значений переменной с двойной точностью равен от 1.7E–308 до 1.7E+308.
Читайте также: