Глава 9. СОВМЕСТИМОСТЬ И
ПРЕОБРАЗОВАНИЕ ТИПОВ ДАННЫХ
Когда в тех или иных операциях или операторах присутствуют данные, относящиеся к различным
типам, возникает вопрос о соответствии типов. В связи с этим говорят об идентичности типов,
совместимости типов и совместимости типов для присваивания. Когда возникают проблемы с
соответствием типов данных, можно осуществить преобразование тех или иных типов. Эти
вопросы и будут рассмотрены в данном разделе.
9.1. Идентичность типов
Идентичность типов требуется от формальных параметров процедур и функций и соответствующих
им фактических параметров во время вызова.
Два типа Т1 и Т2 идентичны в следующих случаях:
- Т1 и Т2 - один и тот же идентификатор типа (например, Integer, Real и т.д.);
- один тип объявляется эквивалентным другому.
Пример.
type
Tl = Boolean;
Т2 = Т1;
ТЗ = Boolean;
Все типы: Tl, T2, ТЗ и Boolean - идентичные типы.
type
Ml = array[1..5] of Integer;
M2 = array[1..5] of Integer;
Типы Ml и М2 - не идентичные типы. Однако VI и V2 - переменные идентичных типов:
var
VI, V2: array[1..5] of Integer;
9.2. Совместимость типов
Совместимость типов требуется в выражениях (в том числе и в операциях отношения).
Два типа Т1 и Т2 совместимы в следующих случаях:
- Т1 и Т2 - один и тот же тип или они идентичны;
- Т1 и Т2 - вещественные типы;
- Т1 и Т2 - целые типы;
- один тип - вещественный, а другой - целый;
- один тип представляет собой тип-диапазон другого;
- оба типа являются типами-диапазонами какого-то одного типа;
- оба типа являются типами-множествами с совместимыми базовыми типами;
- один тип является строкой, а другой - строкой или символом;
- один тип - Pointer, а другой - любой тип-указатель;
- один тип PChar, а другой - массив символов, заканчивающийся символом
с кодом 0 (только при наличии ключа компилятора ($Х+) - см. п. 17.7.1);
- оба типа являются указателями, полученными с помощью адресной операции @,
примененной к величинам идентичных типов (только при наличии ключа компилятора
{$Т+} - см. п. 17.7.1);
- оба типа - процедурные типы с идентичными типами результатов (для типа-функции),
идентичным числом параметров и попарной идентичностью типов этих параметров.
9.3. Совместимость для присваивания
Эта совместимость необходима, когда значение какого-то выражения
присваивается переменной, типизированной константе, функции. Если значение объекта
типа Т2 присваивается объекту типа Т1, то это возможно в следующих случаях:
- Т1 и Т2 - идентичные типы и не являются файловыми типами или структурированными
типами, содержащими компоненты файлового типа на любом уровне структурирования;
- Т1 и Т2 - совместимые порядковые типы и значение типа Т2 находится в
границах возможных значений объекта типа Т1;
- Т1 и Т2 - вещественные типы и значение типа Т2 находится в границах
возможных значений объекта типа Т1;
- Т1 - вещественный тип, а Т2 - целый тип;
- Т1 и Т2 - строки;
- Т1 - строка, а Т2 - символ;
- Т1 и Т2 - совместимые типы-множества и все компоненты значения типа
Т2 находятся в множестве Т1;
- Т1 и Т2 - совместимые указатели;
- Т1 - типа PChar, a T2 - строковая константа (только при наличии ключа
компилятора {$Х+} - см. п. 17.7.1);
- Т1 - типа PChar, a T2 - массив символов, заканчивающийся символом с
кодом 0 (только при наличии ключа компилятора {$Х+} - см. п. 17.7.1);
- Т1 и Т2 - совместимые процедурные типы;
- Т1 - процедурный тип, а Т2 - процедура или функция с идентичным
типом результата, числом параметров и попарной идентичностью типов
этих параметров;
- Т1 и Т2 - объектные типы (см. п. 14) и Т2 - потомок Т1;
- Т1 и Т2 - указатели на объектные типы (см. п. 14) и Т2 - указатель на
потомок типа, на который указывает Т1.
9.4. Преобразование типов
В ряде случаев требуется преобразовать переменную одного типа в переменную другого типа.
В Turbo Pascal такое преобразование осуществляется сравнительно просто, если переменные
обоих типов имеют один и тот же размер. Для этого следует указать идентификатор типа, а
за ним в круглых скобках переменную исходного типа. Если новый тип - структурированный,
можно в случае необходимости выбрать компоненту в соответствии с общими правилами.
Пример.
type
ByteRec = record
Lo, Hi: Byte
end;
WordRec = record
Low, High: Word
end;
PtrRec = record
Ofs, Seg: Word
end;
BytePtr = ^Byte;
var
B: Byte;
W: Word;
L: Longint;
P: Pointer;
begin
W := $1234; (присвоение переменной W значения)
В := ByteRec(W).Lo;
{преобразование переменной типа Word в запись из двух байтов и выделение младшего байта}
ByteRec(W).Hi := 0;
{преобразование переменной типа Word в запись из двух байтов и запись в старший байт
значения 0}
L := $01234567; {присвоение переменной L значения}
W := WordRec(L).Low;
{преобразование переменной типа Longint в запись из двух
слов и выделение младшего слова}
В := ByteRec(WordRec(L).Low).Hi;
{преобразование переменной типа Longint в запись из двух слов, выделение младшего слова,
преобразование его в запись из двух байтов и выделение старшего байта}
В := BytePtr(L)^;
{преобразование переменной типа Longint в указатель и получение значения параметра, на
который он указывает}
Р :=Ptr ($40,$49);
{Присвоение указателю Р значения с помощью стандартной функции Ptr}
W := PtrRec(P).Seg;
{преобразование указателя в запись из двух слов и выделение второго слова (фактически
адреса сегмента)}
Inc(PtrRec(P).Ofs, 4);
{преобразование указателя в запись из двух слов, выделение первого слова (фактически
смещения адреса) и увеличение его величины на 4 с помощью стандартной процедуры Inc}
end.
Такое преобразование возможно не только, когда исходный и окончательный типы имеют
одинаковый размер. Оно возможно также в случае преобразования друг в друга двух порядковых
типов (см. п. 3.2), независимо от их размера, а также преобразования параметра без типа
(см. п. 10.3.4).