Система программирования Turbo Pascal

         

Совместимость и преобразование типов


Как уже неоднократно отмечалось, Турбо Паскаль - это типизированный язык. Он построен на основе строгого соблюдения концепции типов, в соответствии с которой все применяемые в языке операции определены только над операндами совместимых типов. При обсуждении операций над вещественными данными мы уже затрагивали проблему совместимости вещественных и целых типов. Аналогичные проблемы возникают при операциях над строками разной длины, строками и символами и т.д. Ниже приводится более полное определение совместимости типов.

Два типа считаются совместимыми, если:



  • оба они есть один и тот же тип;
  • оба вещественные;
  • оба целые;
  • один тип есть тип-диапазон второго типа;
  • оба являются типами-диапазонами одного и того же базового типа;
  • оба являются множествами, составленными из элементов одного и того же базового типа;
  • оба являются упакованными строками (определены с предшествующим словом PACKED) одинаковой максимальной длины;
  • один тип есть тип-строка, а другой - тип-строка, упакованная строка или символ;
  • один тип есть любой указатель, а другой - нетипизированный указатель;
  • один тип есть указатель на объект, а другой - указатель на родственный ему объект;
  • оба есть процедурные типы с одинаковыми типом результата (для типа-функции), количеством параметров и типом взаимно соответствующих параметров.

Совместимость типов приобретает особое значение в операторах присваивания. Пусть T1 - тип переменной, а Т2 - тип выражения, т.е. выполняется присваивание T1 := T2. Это присваивание возможно в следующих случаях:

  • T1 и T2 есть один и тот же тип и этот тип не относится к файлам или массивам файлов, или записям, содержащим поля-файлы, или массивам таких записей;
  • T1 и T2 являются совместимыми порядковыми типами и значение T2 лежит в диапазоне возможных значений T1;
  • T1 и T2 являются вещественными типами и значение T2 лежит в диапазоне возможных значений T1;
  • T1 - вещественный тип и T2 - целый тип; ,
  • T1 - строка и T2 - символ;
  • T1 - строка и T2 - упакованная строка;
  • T1 и T2 - совместимые упакованные строки;
  • T1 и T2 - совместимые множества и все члены T2 принадлежат множеству возможных значений T1;
  • T1 и T2 - совместимые указатели;
  • T1 и T2 - совместимые процедурные типы;
  • T1 - объект и T2 - его потомок.

В программе данные одного типа могут преобразовываться в данные другого типа. Такое преобразование может быть явным или неявным.

При явном преобразовании типов используются вызовы специальных функций преобразования, аргументы которых принадлежат одному типу, а значение - другому. Таковыми являются уже рассмотренные функции ORD, TRUNC, ROUND, CHR. В гл. 6 описывается функция PTR, преобразующая четырехбайтный целочисленный аргумент к типу-указателю.

В Турбо Паскале может использоваться и более общий механизм преобразования типов, согласно которому преобразование достигается применением идентификатора имени) стандартного типа или типа, определенного пользователем, как идентификатора функции преобразования к выражению преобразуемого типа (так называемое автоопределенное преобразование типов). Например, допустимы следующие вызовы функций:

type

МуТуре = (а, Ь, с, d);

.....

МуТуре (2) 

Integer ('D') 

pointer (longint(a)+ $FF)

Char (127 mod c) 

Byte (k)

При автоопределенном преобразовании типа выражения может произойти изменение длины его внутреннего представления (длина может увеличиться или уменьшиться).

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

type

byt = array [1..2] of Byte;

int = array [1..2] of Integer;

rec = record

x, у : Integer 

end; 

var

vbyt : byt;

vint : int;

vrec : rec; 

begin

byt(vint[1])[2] := 0;

int(vrec)[1] := 256 

end.

Неявное преобразование типов возможно только в двух случаях:

  • в выражениях, составленных из вещественных и целочисленных переменных, последние автоматически преобразуются к вещественному типу, и все выражение в целом приобретает вещественный тип;
  • одна и та же область памяти попеременно трактуется как содержащая данные то одного, то другого типа (совмещение в памяти данных разного типа).

Совмещение данных в памяти может произойти при использовании записей с вариантными полями (см. 4.2.2), типизированных указателей, содержащих одинаковый адрес (см. гл. 6), а также при явном размещении данных разного типа по одному и тому же абсолютному адресу. Для размещения переменной по нужному абсолютному адресу она описывается с последующей стандартной директивой ABSOLUTE, за которой помещается либо абсолютный адрес, либо идентификатор ранее определенной переменной. Абсолютный адрес указывается парой чисел типа WORD, разделенных двоеточием; первое число трактуется как сегмент, второе - как смещение адреса (см. гл. 6). Например:

b : Byte absolute $0000:$0055; w : Longlnt absolute 128:0;

Если за словом ABSOLUTE указан идентификатор ранее определенной переменной, то происходит совмещение в памяти данных разного типа, причем первые байты внутреннего представления этих данных будут располагаться по одному и тому же абсолютному адресу, например:

var

х : Real;

у : array [1..3] of Integer absolute x;

В этом примере переменные X и Y будут размещены, начиная с одного и того же абсолютного адреса. Таким образом, одну и ту же область памяти длиной 6 байт, а следовательно, и размещенные в этой области данные теперь можно рассматривать как данные либо типа REAL, либо как массив из трех данных типа INTEGER. Например, следующая программа выдаст на экран содержимое первых двух байт внутреннего представления вещественного числа п = 3.1415 в виде целого числа:

var

х : Real; у : array[1..3] of Integer absolute x;

begin

х := pi; WriteLn(y[1]) 

end.

На экран будет выдан результат 8578.

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



Содержание раздела