Смекни!
smekni.com

Курс лекций (стр. 20 из 24)

2. Типы описаны как эквивалентные. Т.е. при описании

Type

T1 = array [1..2] of Real;

T2 = T1;

T3 = T2;

все типы Т1,Т2,Т3 будут тождественны.

Однако не только тождественные типы являются совместимыми. Прежде, чем рассматривать совместимость по присваиванию, рассмотрим более общее понятие. Совместимость в ТР трактуется несколько шире. Типы считаются совместимыми, если

- оба типа являются тождественны;

- оба типа являются вещественными;

- оба типа являются целыми;

- один тип является поддиапзоном другого;

- оба типа являются поддиапазонами одного и того же базового типа;

- оба типа являются множествами, составленными из одного и того же базового типа;

- один тип является строковым, а другой символьным или строковым;

- один тип является указателем, а другой указателем или ссылкой.

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

Если говорить о операции присваивания, то в ТР существует еще один вид совместимости – совместимость по присваиванию. Этот вид описывает правила присваивания переменной какого-то значения. Имеется переменная V1 : Type1 и значение V2, которое относится к типу Type2. Переменной может быть присвоено значение (V1 := V2), если выполняется одно из следующих условий:

- Type1 и Type2 тождественные типы, и не один из них не является файловым типом (или структурным типом, содержащим компонент с файловым типом);

- Type1 и Type2 совместимые типы (в смысле, рассмотренном ранее), относящиеся к порядковым, и значения типа Type2 попадают в диапазон возможных значений Type1;

- Type1 и Type2 – вещественные типы и значения типа Type2 попадают в диапазон возможных значений Type1;

- Type1 – вещественный тип, Type2 – целочисленный тип;

- Type1 и Type2 – строковые типы;

- Type1 – строковый тип, Type2 – символьный тип;

Есть еще 4 правила, относящихся к множествам, указателям и объектам.

- Type1 и Type2 совместимые множества и все члены значения множества типа Type2 попадают в диапазон возможных значений Type1;

- Type1 и Type2 совместимые адресные типы;

- Тип объекта Type2 совместим по присваиванию с типом объекта Type1, если Type2 находится в области типа объекта Type1.

- Тип ссылки Ptr2, указывающий на тип объекта Type2, совместим по присваиванию с типом ссылки Ptr2, указывающим на тип объекта Type1, если Type2 находится в области типа объекта Type1.

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

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

При явном преобразовании используются вызовы специальных функций, аргументы которых принадлежат одному типу, а значения (результат) другому. Таковыми являются, например, уже рассмотренные функции ORD, TRUNC, CHR…

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

Type

M2Word = array[1..2] of Word;

M4Byte = array[1..4] of Byte;

Var

V1 : M2Word;

V2 : M4Byte;

V3 : LongInt;

V4 : Word;

Begin

V3 := 100;

V1 := M2Word(V3);

V2 := M4Byte(V3);

V4 := Word(V1[1]);

End.

Переменные V1,V2,V3 в памяти занимают 4 байта, переменная V4 - 2 байта. Сначала задаем значение переменной V3. Две следующие строки помещают значение LongInt либо в два слова, либо в четыре байта. В данном примере V1[1]=100, V1[2]=0, т.к. длина значащих двоичных разрядов в V3 меньше, чем длина Word. Если будет больше, то такого соответствия не будет, т.к. число будет разбито на два в двоичном представлении. Затем первый элемент массива V1 помещается в переменную V4. Т.о. данный метод позволяет нарушить правила совмещения типов при условии, что соответствующие значения совместимы в машинном представлении. Приведение типа переменной может стоять как слева, так и справа M2Word(V3)[2] := 3. При этом V3 состоит из двух байтов: младший 0..01100100 = (100)10, старший 0..00000011 = (3)10, в сумме 0..00000011 0..01100100 = (196708)10;

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

Например, Integer('Y') - код символа 'Y' в формате Integer. Этот символ хранится как код 89 и занимает один байт. Конструкция Integer('Y') представляет собой значение 89 в формате целого числа со знаком (в двух байтах). При преобразовании типа значения соблюдение размеру уже не нужно. Новый тип может быть шире, а может быть короче, чем естественный тип значения. При приведении значения в более широкий тип значения будут целиком записаны в младшие байты, что естественно сохранит само значение. Когда значение приводится к более короткому типу, от него берутся только самые младшие байты, старшие игнорируются. Преобразование типа значения внешне похоже на преобразование типа переменной. Но эффект от него несколько иной (за счет возможности изменения размера), и иные ограничения. В частности тип значения и задаваемый тип должны быть порядковыми. Кроме того, преобразование значения не может появиться в левой части.

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

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

2. Одна и та же область памяти попеременно трактуется как содержащая данные то одного, то другого типа (совмещение в памяти данных разного типа).

Совмещение данных в памяти, в частности, возможно при явном размещении данных разного типа по одному и тому же абсолютному адресу (а также при использовании записей с вариантными полями, типизированных указателей, содержащих одинаковый адрес). Для размещения переменной по нужному абсолютному адресу она описывается с последующей стандартной директивой ABSOLUTE, за которой помещается либо абсолютный адрес, либо имя ранее определенной переменной (Адрес указывается парой чисел типа Word, разделенных двоеточием; первое трактуется как сегмент, второе как смещение (вся память 1 Мбайт для ТР 7.0 разбивает на сегменты длиной 65536 байт (64К), каждому сегменту соответствует непрерывная и отдельно адресуемая область памяти. Сегменты могут следовать один за другим без промежутков или с некоторым интервалом, или перекрывая друг друга. Сегменты адресуют память с точностью до 16 байт, а смещение с точностью до байта): w : LongInt absolute 128:0. При таком описании переменной ее значение помещается в определенную область памяти. Затем эту область памяти уже можно рассматривать как переменную другого типа. Это бывает удобно, когда есть желание использовать некоторую функцию (или процедуру) применительно к переменным различного типа.

8. УПРАВЛЯЮЩИЕ СТРУКТУРЫ ЯЗЫКА TURBO PASCAL

В этом разделе будут рассмотрены управляющие операторы ТР (условный оператор, операторы циклов, выбора и др.), а также вопросы построения процедур и функций, и принципы построения модулей.

ПРОСТОЙ И СОСТАВНОЙ ОПЕРАТОР

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

Два последовательных оператора должны разделяться точкой с запятой. Этот символ имеет смысл конца оператора, в частности, он разделяет операторы при записи в строку:

a := 11; b:=a*a; Write(a,b);

Если какое-то действие мыслится как единое (например, присваивание значений элементам массива), но реализуется несколькими различными операторами, то эти операторы могут быть представлены как составной оператор. Составной оператор - это последовательность операторов, перед которой стоит слово begin, а после слово - end. Слова begin и end сами не являются операторами, поэтому после begin и перед end точка с запятой не ставится. Чтобы оформить предыдущий пример в один, но составной оператор, необходимо как бы заключить их в операторные скобки begin...end:

begin

a := 11;

b := a*a;

Write(a,b)

end;

Составной оператор может содержать любое допустимое число простых операторов. Кроме того, он допускает вложенность, т.е. может содержать внутри себя другие составные операторы (в этом случае нужно лишь, чтобы внутренний составной оператор открывался позже, чем внешний, а закрывался - раньше).

Пустой оператор не содержит никаких действий, просто в программу добавляется дополнительная точка с запятой (например, в последнем примере перед end). В основном пустой оператор используется для передачи управления в конец составного оператора.

УСЛОВНЫЙ ОПЕРАТОР

Условный оператор имеет структуру

if <условие> then <оператор1> else <оператор2>

где if, then, else - зарезервированные слова (если...то...иначе);

<условие> - логическое значение True или False, представленное константой, переменной или логическим выражением.

Если условие представлено значением True, то выполняется <оператор1>, следующий за словом then. Но если условие не выполняется, т.е. представлено значением False, то будет выполняться <оператор2> за словом else. Например,