Длина, байт
|
Название
|
Количество
значащих цифр
|
Диапазон
значений
|
8
4
8
10
8
8
|
Real
Single
Double
Extended
Comp
Currency
|
15…16
7…8
15…16
19…20
19…20
19…20
|
5.0*10e-324…1.7*10e308
1.5*10e-45…3.4*10e38
5.0*10e324…1.7*10e308
3.4*10-4951…1.1*10e4932
-2e63…+2e63-1
+/-922 337
203 685477,5807
|
В предыдущих версиях Delphi 1...3 тип Real занимал 6 байт и имел
диапазон значений от 2,9*10-39 до 1,7*1038. В версиях 4 и 5 этот тип
эквивалентен типу Double. Если требуется (в целях совместимости)
использовать 6-байтных Real, нужно указать директиву компилятора
{SREALCOMPATIBILITY ON}.
Как видно из табл. 1.4, вещественное число в Object Pascal занимает от 4
до 10 смежных байт и имеет следующую структуру в памяти ПК.
Здесь s - знаковый разряд числа; е - экспоненциальная часть; содержит
двоичный порядок; m - мантисса числа.
Мантисса m имеет длину от 23 (для single) до 63 (для Extended)
двоичных разрядов, что и обеспечивает точность 7...8 для single и
19...20 для Extended десятичных цифр. Десятичная точка (запятая)
подразумевается перед левым (старшим) разрядом мантиссы, но при действиях с
числом ее положение сдвигается влево или вправо в соответствии с двоичным
порядком числа, хранящимся в экспоненциальной части, поэтому действия над
вещественными числами называют арифметикой с плавающей точкой (запятой).
Отметим, что арифметический сопроцессор всегда обрабатывает числа в
формате Extended, а три других вещественных типа в этом случае
получаются простым усечением результатов до нужных размеров и применяются в
основном для экономии памяти.
Особое положение в Object Pascal занимают типы comp и Currency,
которые трактуются как вещественные числа с дробными частями фиксированной
длины: в comp дробная часть имеет длину 0 разрядов, т. е. просто
отсутствует, в currency длина дробной части -4 десятичных разряда.
Фактически оба типа определяют большое целое число со знаком, сохраняющее
19...20 значащих десятичных цифр (во внутреннем представлении они занимают 8
смежных байт). В то же время в выражениях comp и currency
полностью совместимы с любыми другими вещественными типами: над ними определены
все вещественные операции, они могут использоваться как аргументы
математических функций и т. д. Наиболее подходящей областью применения этих
типов являются бухгалтерские расчеты.
1.1.3 Тип дата-время
Тип дата-время определяется стандартным идентификатором TDateTime
и предназначен для одновременного хранения и даты, и времени. Во внутреннем
представлении он занимает 8 байт и подобно currency представляет собой
вещественное число с фиксированной дробной частью: в целой части числа хранится
дата, в дробной - время. Дата определяется как количество суток, прошедших с 30
декабря 1899 года, а время - как часть суток, прошедших с 0 часов, так что
значение 36444,837 соответствует дате 11.10.1999 и времени 20:05. Количество
суток может быть и отрицательным, однако значения меньшие -693594 (соответствует
дате 00.00.0000 от Рождества Христова) игнорируются функциями преобразования
даты к строковому типу.
Над данными типа TDateTime определены те же операции, что и над
вещественными числами, а в выражениях этого типа могут участвовать константы и
переменные целого и вещественного типов.
Поскольку тип TDateTime совместим с форматом вещественных чисел,
можно без труда определить дату, отстоящую от заданной на сколько-то дней
вперед или назад: для этого достаточно соответственно прибавить к заданной дате
или отнять от нее нужное целое число.
1.2 Структурированные типы
Любой из структурированных типов (а в Object Pascal их четыре: массивы,
записи, множества и файлы) характеризуется множественностью образующих этот тип
элементов. Каждый элемент, в свою очередь, может принадлежать
структурированному типу, что позволяет говорить о возможной вложенности типов.
В Object Pascal допускается произвольная глубина вложенности типов, однако
суммарная длина любого из них во внутреннем представлении не должна превышать 2
Гбайт [16-разрядные версии операционной системы Windows З.х используют так
называемую “сегментную” модель памяти, поэтому в Delphi 1 любой
структурированный тип не может занимать более одного сегмента (65536 байт)].
В целях совместимости со стандартным Паскалем в Object Pascal разрешается
перед описанием структурированного типа ставить зарезервированное слово packed,
предписывающее компилятору по возможности экономить память, отводимую под
объекты структурированного типа; но компилятор фактически игнорирует это
указание: “упаковка” данных в Object Pascal осуществляется автоматачески везде,
где это возможно.
1.2.1 Массивы
Массивы в Object Pascal во многом схожи с аналогичными типами данных в
других языках программирования. Отличительная особенность массивов заключается
в том, что все их компоненты суть данные одного типа (возможно,
структурированного). Эти компоненты можно легко упорядочить и обеспечить доступ
к любому из них простым указанием его порядкового номера.
Описание типа массива задается следующим образом:
<имя типа> = array [ <сп.инд.типов> ] of <тип>;
Здесь <имя типа> - правильный идентификатор; array, of -
зарезервированные слова {массив, из); <сп.инд.типов> - список из одного
или нескольких индексных типов, разделенных запятыми; квадратные скобки,
обрамляющие список, - требование синтаксиса; <тип> - любой тип Object
Pascal.
В качестве индексных типов в Object Pascal можно использовать любые
порядковые типы, имеющие мощность не более 2 Гбайт (т. е. кроме LongWord
и Int64)
Глубина вложенности структурированных типов вообще, а, следовательно, и
массивов - произвольная, поэтому количество элементов в списке индексных типов
(размерность массива) не ограничено, однако суммарная длина внутреннего
представления любого массива не может быть больше 2 Гбайт. В памяти ПК элементы
массива следуют друг за другом так, что при переходе от младших адресов к
старшим наиболее быстро меняется самый правый индекс массива.
В Object Pascal можно одним оператором присваивания передать все элементы
одного массива другому массиву того же типа.
1.2.2 Записи
Запись - это структура данных, состоящая из фиксированного
количества компонентов, называемых полями записи. В отличие от массива
компоненты (поля) записи могут быть различного типа. Чтобы можно было ссылаться
на тот или иной компонент записи, поля именуются.
Структура объявления типа записи такова:
<имя типа> = record <сп.полей> end;
Здесь <имя типа> - правильный идентификатор; record/ end -
зарезервированные слова {запись, конец); <сп.полей> - список полей;
представляет собой последовательность разделов записи, между которыми ставится
точка с запятой.
Каждый раздел записи состоит из одного или нескольких идентификаторов
полей, отделяемых друг от друга запятыми.
Предложение case ... of, открывающее вариантную часть, внешне
похоже на соответствующий оператор выбора, но на самом деле лишь играет роль
своеобразного служебного слова, обозначающего начало вариантной части. Именно
поэтому в конце вариантной части не следует ставить end как пару к case...of.
(Поскольку вариантная часть - всегда последняя в записи, за ней все же стоит
end, но лишь как пара к record). Ключ выбора в предложении case…of
фактически игнорируется компилятором: единственное требование, предъявляемое к
нему в Object Pascal, состоит в том, чтобы ключ определял некоторый стандартный
или предварительно объявленный порядковый тип.
Имена полей должны быть уникальными в пределах той записи, где они
объявлены, однако, если записи содержат поля-записи, т. е. вложены одна в
другую, имена могут повторяться на разных уровнях вложения.
1.2.3 Множества
Множества - это наборы однотипных логически связанных друг с другом
объектов. Характер связей между объектами лишь подразумевается программистом и
никак не контролируется Object Pascal. Количество элементов, входящих во
множество, может меняться в пределах от 0 до 256 (множество, не содержащее
элементов, называется пустым). Именно непостоянством количества своих элементов
множества отличаются от массивов и записей.
Два множества считаются эквивалентными тогда и только тогда, когда все их
элементы одинаковы, причем порядок следования элементов в множестве
безразличен. Если все элементы одного множества входят также и в другое,
говорят о включении первого множества во второе. Пустое множество включается в
любое другое.
Описание типа множества имеет вид:
<имя типа> = set of <базовый тип>;
Здесь <имя типа> - правильный идентификатор; set, of -
зарезервированные слова (множество, из); <базовый тип> - базовый тип
элементов множества, в качестве которого может использоваться любой порядковый
тип, кроме Word, Integer, Longint, Int64.
Для задания множества используется так называемый конструктор множества:
список спецификаций элементов множества, отделенных друг от друга запятыми;
список обрамляется квадратными скобками. Спецификациями элементов могут быть
константы или выражения базового типа, а также тип-диапазон того же базового
типа.
Внутреннее устройство множества таково, что каждому его элементу ставится
в соответствие один двоичный разряд (один бит); если элемент включен во
множество, соответствующий разряд имеет значение 1, в противном случае - 0. В
то же время минимальной единицей памяти является один байт, содержащий 8 бит,
поэтому компилятор выделил множествам по одному байту, и в результате мощность
каждого из них стала равна 8 элементам. Максимальная мощность множества - 256
элементов. Для таких множеств компилятор выделяет по 16 смежных байт.
И еще один эксперимент: измените диапазон базового типа на 1..256. Хотя
мощность этого типа составляет 256 элементов, при попытке компиляции программы
компилятор сообщит об ошибке: Sets may have at most 256 elements (Множества
могут иметь не более 256 элементов) т. к. нумерация элементов множества
начинается с нуля независимо от объявленной в программе нижней границы.
Компилятор разрешает использовать в качестве базового типа целочисленный
тип-диапазон с минимальной границей 0 и максимальной 255 или любой
перечисляемый тип не более чем с 256 элементами (максимальная мощность
перечисляемого типа - 65536 элементов).
1.3 Строки
Для обработки текстов в Object Pascal используются следующие типы:
короткая строка shortString или string [n] , где n <=
255;
длинная строка string;
широкая строка WideString;
нуль-терминальная строка pchar.
Общим для этих типов является то, что каждая строка трактуется как
одномерный массив символов, количество символов в котором может меняться в
работающей программе: для string [n] длина строки меняется от 0 до n, для string
и pchar - от 0 до 2 Гбайт.
В стандартном Паскале используются только короткие строки String [n].
В памяти такой строке выделяется n+i байт, первый байт содержит текущую длину
строки, а сами символы располагаются, начиная со 2-го по счету байта. Поскольку
для длины строки в этом случае отводится один байт, максимальная длина короткой
строки не может превышать 255 символов. Для объявления короткой строки
максимальной длины предназначен стандартный тип ShortString (эквивалент String[255]).
В Windows широко используются нуль-терминальные строки, представляющие
собой цепочки символов, ограниченные символом #о. Максимальная длина такой
строки лимитируется только доступной памятью и может быть очень большой.
В 32-разрядных версиях Delphi введен новый тип string, сочетающий
в себе удобства обоих типов. При работе с этим типом память выделяется по мере
надобности (динамически) и ограничена имеющейся в распоряжении программы
доступной памятью.
1.4 Указатели и динамическая память
1.4.1 Динамическая память
Динамическая память - это оперативная память ПК, предоставляемая программе при
ее работе. Динамическое размещение данных означает использование динамической
памяти непосредственно при работе программы. В отличие от этого статическое
размещение осуществляется компилятором Object Pascal в процессе компиляции
программы. При динамическом размещении заранее не известны ни тип, ни
количество размещаемых данных.
1.4.2 Указатели
Оперативная память ПК представляет собой совокупность ячеек для хранения
информации - байтов, каждый из которых имеет собственный номер. Эти номера
называются адресами, они позволяют обращаться, к любому байту памяти. Object
Pascal предоставляет в распоряжение программиста гибкое средство управления
динамической памятью - так называемые указатели. Указатель - это переменная, которая
в качестве своего значения содержит адрес байта памяти. С помощью указателей
можно размещать в динамической памяти любой из известных в Object Pascal типов
данных. Лишь некоторые из них (Byte, Char, ShortInt, Boolean) занимают
во внутреннем представлении один байт, остальные - несколько смежных. Поэтому
на самом деле указатель адресует лишь первый байт данных.
Как правило, указатель связывается с некоторым типом данных. Такие
указатели будем называть типизированными. Для объявления типизированного указателя
используется значок ^, который помещается перед соответствующим типом.
В Object Pascal можно объявлять указатель и не связывать его при этом с
каким-либо конкретным типом данных. Для этого служит стандартный тип pointer,
например:
var
р: Pointer;
Указатели такого рода будем называть нетипизированньти. Поскольку
нетипизированные указатели не связаны с конкретным типом, с их помощью удобно
динамически размещать данные, структура и тип которых меняются в ходе работы
программы.
Как уже говорилось, значениями указателей являются адреса переменных в
памяти, поэтому следовало бы ожидать, что значение одного указателя можно
передавать другому. На самом деле это не совсем так. В Object Pascal можно
передавать значения только между указателями, связанными с одним и тем же типом
данных.
1.4.3 Выделение и освобождение динамической памяти
Вся динамическая память в Object Pascal рассматривается как сплошной
массив байтов, который называется кучей.
Память под любую динамически размещаемую переменную выделяется процедурой
New. Параметром обращения к этой процедуре является типизированный указатель. В
результате обращения указатель приобретает значение, соответствующее адресу,
начиная с которого можно разместить данные. Значение, на которое указывает
указатель, т. е. собственно данные, размещенные в куче, обозначаются значком ^,
который ставится сразу за указателем. Если за указателем нет значка ^, то
имеется в виду адрес, по которому размещены данные. Имеет смысл еще раз
задуматься над только что сказанным: значением любого указателя является адрес,
а чтобы указать, что речь идет не об адресе, а о тех данных, которые размещены
по этому адресу, за указателем ставится ^ (иногда об этом говорят как о
разыменовании указателя).
Динамически размещенные данные можно использовать в любом месте
программы, где это допустимо для констант и переменных соответствующего типа
Динамическую память можно не только забирать из кучи, но и возвращать
обратно. Для этого используется процедура Dispose. Например, операторы
Dispose(pJ);
Dispose(pR);
вернут в кучу память, которая ранее была закреплена за указателями pJ и
pR (см. выше).
Замечу, что процедура Dispose (pPtr) не изменяет значения указателя pPtr,
а лишь возвращает в кучу память, ранее связанную с этим указателем. Однако
повторное применение процедуры к свободному указателю приведет к возникновению
ошибки периода исполнения. Освободившийся указатель программист может пометить
зарезервированным словом nil.
1.5 Псевдонимы типов
Для любого типа можно объявить сколько угодно псевдонимов. Например:
type
TMyInteger = Integer;
В дальнейшем псевдоним можно использовать так же, как и базовый тип:
var
Mylnt: TMyInteger;
begin
Mylnt := 2*Round(pi);
end;
Такого рода псевдонимы обычно используются для повышения наглядности кода
программы. Однако в Object Pascal можно объявлять строго типизированные
псевдонимы добавлением зарезервированного слова type перед именем базового
типа:
type
TMyIntegerType = type Integer;
var
MylntVar: TMyIntegerType;
С точки зрения компилятора, типизированные псевдонимы совместимы с
базовым типом в различного рода выражениях, но фактически они объявляют новый
тип данных, поэтому их нельзя использовать в качестве формальных параметров
обращения к подпрограммам вместо базового типа. Если, например, объявлена процедура
function MylntFunc(APar: integer): Integer;
begin
end;
то такое обращение к ней
MylntFunc(MylntVar)
будет расценено компилятором как ошибочное.
Строго типизированные псевдонимы заставляют компилятор вырабатывать
информацию о типе для этапа прогона программы (RTTI - Run-Time Type
Information). Эта информация обычно используется средой Delphi для обеспечения
функционирования разного рода редакторов.