Pascal является языком с сильной системой типизации. В нём предусмотрено большое количество простых и сложных типов данных, а так же способ определения типов данных в блоке описаний типа.
I. Простые (скалярные) типы
1. Целые типы (ShortInt, Integer, LongInt, Byte, Word).
2. Вещественные типы (Real, Single, Double, Extended, Comp).
5. Строковый (String, String [n]).
6. Адресный тип (указатель) (Pointer).
Все перечисляемые выше типы могут участвовать в определении сложных типов.
II. Сложные (структурированные) типы
3. Запись (record).
4. Объект (object).
5. Файл
Основываясь на указанных типах можно создать собственные новые типы данных. Во время выполнения операций над переменными необходимо соблюдать правила совместимости и преобразования типов.
Для записи данных и кодов операций в компьютере используется двоичная система счисления. Это определяется физическими процессами, используемыми в ПК.
Система счисления – это совокупность приёмов и правил для обозначения и наименования числа. Системы счисления делятся на две группы: позиционные и непозиционные.
В позиционной системе количественный эквивалент значения символа зависит от его места (позиции) в числе. Наиболее распространены в на практике две системы: десятичную используют люди, а двоичную – компьютеры.
Для десятичной системы счисления используются 10 цифр [0,1,2,3, 4,5,6,7, 8,9].
Двоичной (бинарной) системой счисления называется такая позиционная система счисления, при которой для записи чисел используется только две цифры (два состояния): 0 и 1.
Для представления чисел, больших старшей цифры, используется следующая позиция, значение которой необходимо умножать на количество используемых цифр в данной системе счисления. Определенное число может быть записано в любой системе счисления, но по-своему.
Например, число 5, используемой обычно десятичной системы, в двоичной системе запишется так
То есть может быть записано в компьютере с помощью двух единиц и нуля, но запись длиннее. Для обозначения разряда или группы разрядов, записанных в компьютере, используются термины:
· Единицей информации, которая может равняться 0 или 1 является бит.
· Минимальной адресуемый элемент данных в ПК состоит из 8 битов и называется байтом.
Простые типы отличаются друг от друга, прежде всего, количеством байтов, отводимых на данные этих типов. Далее опишем все простые типы языка Pascal.
Значение переменной или константы в программе может быть целое число, например +123, -15, 0, 17, то есть число без точки со знаком + или без него. Соответственно для различных целей предусмотрено пять типов целых данных.
Описание целых типов данных
Имя типа |
Размер в байтах |
Диапазон |
ShortInt |
1 |
-128…127 |
Integer |
2 |
-32768…32767 |
LongInt |
4 |
-2147483648…2147483648 |
Byte |
1 |
0…255 |
Word |
2 |
0…65535 |
То есть переменные первых трёх типов являются целыми числами различной длины со знаком, а двух последних типов – целыми числами без знака. Начинающих обычно удивляет такое разделение, однако, очевидно, что типы Byte и Word можно использовать для переменных, означающих “номер”, а использование типов с небольшим диапазоном значений приводит к экономии памяти ПК.
Если вы не можете сориентироваться, какой из целых типов выбрать для использования в своей программе, – выберите Integer.
В языке Pascal для переменных целого типа определены операции побитовой обработки информации, которые преобразуют отдельные биты двоичного представления целого числа (например, инверсия битов, логические операции и, или, исключающие сдвиг битов налево, направо). При использовании этих операций надо хорошо представлять, как именно записано целое число в памяти, так как отрицательные числа хранятся в так называемом “обратном отсчете”, а значения некоторых типов хранятся в “перевёрнутом” виде (младшие разряды записаны первыми).
Целые числовые константы могут быть записаны в 16-ричном виде. Например, число 255 можно записать $FF.
Значениями переменных и констант могут быть дробные числа, то есть числа с точкой +123.6, -0.015, 15.
Вещественное число хранится в машине в экспоненциальной форме с плавающей точкой. Различают пять вещественных типов.
Описание вещественных типов данных
Имя типа |
Размер в байтах |
Число значащих цифр в мантиссе |
Диапазон |
Real |
6 |
11 |
± |
Single |
4 |
7 |
± +1.5E-45…+3.4E38 |
Double |
8 |
15 |
± +5.0E-324…+1.7E308 |
Extended |
10 |
19 |
± +3.4E-4932…+1.1E432 |
Comp |
8 |
19 |
-2E64+1…2E63-1 |
Очевидно, что вещественные типы различаются диапазоном значений и числом значащих цифр в мантиссе. Большое число значащих цифр очень важно при проведении точных вычислений, так как при вычислениях ПК округляет последнюю значащую цифру, что приводит к накоплению ошибок. Последние значащие цифры становятся неверными и чем больше цифр, тем меньше ошибка.
Тип Comp может содержать только целые числа от -2 63 +1 до +263-1, но эти числа хранятся в вещественном формате, поэтому тип Comp считается вещественным. С данными типа Comp можно обращаться так же, как с данными других вещественных типов, но дробная часть числа при этом автоматически отбрасывается.
Важное замечание: В таблице приведены совместимые типы, поддерживаемые Turbo Pascal. Точность и пределы вещественных типов зависимы от компьютерной платформы: типа процессора и режима эмуляции математического сопроцессора. Так для 32-разрядных ПК под Windows тип Real автомасштабируется до типа Double.
Уточнить пределы типов можно с помощью следующих функций (пример):
High (целый тип) |
возвращает наибольшее возможное значение данного типа |
Low (целый тип) |
возвращает наименьшее возможное значение данного типа |
SizeOf (тип или переменная) |
возвращает размер в байтах заданного типа или заданной переменной |
Часто встречаются задачи, которые предполагают выполнение различных действий в зависимости от какого-либо условия, например
.
В этой задаче, если х>1, то
функция считается по формуле
,
а если нет, то по формуле
.
Таким образом можно определить результаты сравнения х и 1:если х действительно
выше 1, то результат “правда” или – True, а если не больше, то результат
ложь или – False.
Значения True и False являются логическими константами, а переменная, значением которой могут быть True и False - логическая переменная типа Boolean. В памяти на такие переменные отводится один байт. Если значение переменной True, то в память записывают 1, если False – то 0, т.о. False < True. В область памяти, занимаемую этими переменными можно записать и числа.
Описание логического типа данных
Имя типа |
Размер в байтах |
Диапазон |
Boolean |
1 |
True, False |
Пример:
Var A: Boolean;
Begin
A := true;
A := 1=2; // в результате A станет равно false
End.
Чтобы определить, какое значение принимает логическая переменная можно использовать функцию ord:
n:=ord(L),
где L – переменная логического типа. n=0, если L=False, n=1, если L=True.
Существует функция, определенная для целочисленных аргументов и имеющая логическое значение:
Odd(x)
Она возвращает TRUE, если значение x нечетное, и FALSE, если оно четное.
Этот тип данных, состоящих из одного символа. На него отводится один байт памяти.
Описание символьного типа данных
Имя типа |
Размер в байтах |
Диапазон |
Char |
1 |
Все символы кодовой таблицы |
В тексте программы значения переменных и констант символьного типа заключают в апострофы, например, ‘a’, ‘Ш’, ’9’, либо в специальных функциях указывают номера (кода) символа, например #55.
Символы, как любые однотипные данные могут быть объединены в массивы.
Это тип данных, значением которых является совокупность нескольких символов, записанных в апострофах, например:
‘строчка’, ‘______’, ‘12345 вышел зайчик погулять’.
Описание строкового типа данных
Имя типа |
Размер в байтах (длина строки) |
Диапазон |
String String[n] |
255 n |
Все символы
|
Причем, если значение типа описывается просто служебным словом string, то переменными являются строки длиной 255 символов, а если значение типа имеет вид string [n], то описываются строки длиной n символов.
Перечисляемый тип задается непосредственным перечислением значений, которые может принимать переменная данного типа.
Var
Color : (red, blue, green);
Animal : (dog, cat, mouse);
R : (I, II, III, IV);
Интервальный тип данных задается через две константы (целочисленные или символьные) разделенные двумя точками (..), которые определяют границы изменения переменных данного типа. Значение первой константы должно быть меньше второй.
Var
a: 0..9;
small_symbol : ‘a’..’z’;
Каждая переменная интервального типа занимает 1 байт. Этот тип является неким подтипом порядковых скалярных типов (Byte, Integer, Char, Boolean и т.п.). Но, использование этого типа вместо стандартных, позволяет сэкономить память.
Описание одномерного массива имеет вид:
Имя_массива : ARRAY [тип индекса] OF тип элемента;
Здесь тип индекса - ShortInt, Byte, Char, Boolean или интервальный тип (что связано с ограничением размера массива); тип элемента - любой тип, в том числе и массив. Если элементы массива сами имеют тип массив, то размерность такого массива больше чем 1.
Приведем примеры:
VAR a : ARRAY[1..10000] OF BYTE;
- массив a из 10000 элементов, каждый из которых может принимать значение от 0 до 255.
VAR a : ARRAY[Char] OF 1..5;
- массив из 256 элементов, каждый из которых есть целое число от 1 до 5, индексы элементов изменяются от #0 до #255.
Или даже так:
CONST Max = 99; Min = 10;
IndexMin=-10; IundexMax=5;
TYPE Nums = Min..Max;
Indextype = Indexmin..indexmax;
TYPE ArrayType = ARRAY[Indextype] OF Nums;
VAR a : ArrayType;
- массив из 15 элементов с индексами от -10 до 5, каждый элемент - целое положительное число из двух цифр от 10 до 99.
У многомерных массивов размерностью, или количеством измерений массива, называется количество индексов у элемента массива. Двумерный массив можно описать, например, так :
VAR a : ARRAY[1..10] OF ARRAY[1..20] OF Real;
или
VAR a : ARRAY[1..10,1..20] OF Real;
На языке Pascal есть возможность описать ваш собственный тип, делая это в блоке описания типа, который начинается словом type. В программе может быть сколько угодно операторов type. Важно, чтобы этот блок находился в разделе описаний до блока var, где переменным присваиваются введенные новые типы.
Общая форма оператора Type:
Type имя_типа = описание типа;
Примеры (название новых типов старайтесь давать осмысленными):
type
Stroka=array[1..10] of char;
Chushki=(Nifnif, Nufnuf, Nafnaf);
Alphavit=’А’..’Я’;
var
slova : stroka; name_svin : chushki; ABC : alphavit;
В этом блоке описание типов:
1. описан массив из 10 символов – тип stroka, что точности соответствует типу string [10].
2. описан перечисляемый тип chushki (чушки) через значения переменных этого типа. Введение таких типов улучшает читаемость программы. К переменным этого типа применима функция Ord(x), Succ(x), Pred(x), однако переменные этого типа запрещено вводить с клавиатуры и выводить на экран.
3. описан интервальный тип – диапазон Alphavit. Значениям переменных данного типа будут заглавные буквы от А до Я. Функция Ord к ним так же применима. Значения переменных этого типа могут выводиться на экран и вводится с клавиатуры, если этот диапазон взят из типа, значение которого могут выводиться на экран.
Понятие множества в Паскале очень близко к математическому определению: множество - это совокупность однотипных неиндексированных объектов.
Тип множества в Pascal описываются в виде:
SET OF тип;
где тип - базовый для этого множества тип, т.е. тип элементов множества. Базовый тип должен быть порядковым типом мощностью не более 256 (т.е. допускающий не более 256 различных значений). Таким образом, базовым типом для множества могут быть: типы Char, Boolean, Byte и все производные от Byte интервальные типы.
Неименованные константы типа множество записываются в виде:
[ подмножество , подмножество , ... ];
где подмножество - это либо отдельное значение, либо диапазон. Диапазон записывается как начальное значение .. конечное значение.
Например, константу-множество, содержащую числа 0, 1, 2, 3, 4, 8, 12, 13, 14, 15, 16, 22 можно описать как:
[0,1,2,3,4,6,12,13,14,15,16,22];
или
[0..4,6,12..16,22];
Опишем несколько переменных и типизированных констант:
TYPE MySet = SET OF 0..111;
VAR a : SET OF Char;
b : MySet;
CONST c : SET OF Char = ['А'..'Я'];
d = [1,2,3,4,5 ]
К множествам применимы специальные операции (присвоения, объединение, пересечение и т.п.)
Существует еще одна операция, связанная с множествами - операция IN, она применяется к скалярной величине и множеству:
выражение IN множество
Здесь выражение - любое выражение базового для данного множества типа, результат операции - TRUE, если такой элемент есть во множестве, и FALSE - в противном случае.
Решим задачу: ввести массив символов и подсчитать, сколько в нем русских и латинских букв.
TYPE Letters = SET OF Char;
CONST Lat = ['a'..'z','A'..'Z']; Rus = ['а'..'п','р'..'я','А'..'Я'];
VAR c : Char;
CONST RSum : Word=0; LSum : Word=0;
BEGIN
WRITE('Введите массив символов, затем нажмите Enter ');
REPEAT READ(c);
IF c IN Lat THEN INC(LSum) ELSE IF c IN Rus THEN INC(RSum);
UNTIL c=#10;
WRITELN('Латинских букв ',LSum,' русских букв ',RSum);
END.
В Free PASCAL также определен адресный тип Pointer - указатель. Переменные типа Pointer описываются как
var p: Pointer;
Они содержат адрес какого-либо элемента программы и занимают 4 байта, при этом адрес хранится как два слова, одно из них определяет сегмент памяти, второе - смещение. Переменную типа указатель можно описать другим способом – через новый тип.
type NameType= ^T;
var p: NameType;
Над указателями не определено никаких операций, кроме проверки на равенство или неравенство.
Процедурные типы разработаны для передачи имен функций или процедур в качестве фактических параметров при обращении к другим функциям и процедурам. Т.е. Паскаль допускает наличие у процедур и функций параметров, которые сами являются процедурами или функциями. Для их описания используется заголовок подпрограммы, в котором пропущено ее имя.
type
fun_1=function (x, y : real) : real;
proc_1=procedure(x, y : real; var z: real);
У передаваемой функции должен присутствовать описатель far. И все пpоцедуpы и функции, использованные в пpогpамме, как аргументы, должны быть откомпилированы с опцией {$F+}.
Приведем пример пpогpаммы, которая выводить таблицу значений некоторой функции:
TYPE FuncType=FUNCTION(Arg:Real):Real;
{$F+}
FUNCTION F_Cos(x:Real):Real; BEGIN F_Cos:=Cos(x); END;
FUNCTION F_Sin(x:Real):Real; BEGIN F_Sin:=Sin(x); END;
FUNCTION F_Tg(x:Real):Real; BEGIN F_Tg:=Sin(x)/Cos(x); END;
{$F-}
PROCEDURE PrintFunc(Xmin,Xmax:Real; n:Word; F:FuncType; Header:STRING);
VAR h,x:Real; i:Word;
BEGIN WRITELN; WRITELN(Header); h:=(Xmax-Xmin)/n;
FOR i:=0 TO n DO BEGIN
x:=i*h+Xmin; WRITELN(x:10:5,F(x):10:5); END;
WRITELN('Hажмите ENTER'); READLN;
END;
BEGIN PrintFunc(0,Pi,20,F_Cos,'Значения функции cos');
PrintFunc(0,Pi/2,20,F_Sin,'Значения функции sin');
PrintFunc(0,Pi/4,10,F_Tg,'Значения функции tg');
END.
Подробнее остальные структурированные типы (такие как одно- и двумерные массивы, записи, файлы и объекты) описаны в соответствующих разделах данного пособия.
§ Г.15 Совместимость и преобразование типов
Как уже неоднократно отмечалось, Паскаль - это строгий типизированный язык. Он построен на основе соблюдения концепции типов, в соответствии с которой все применяемые в языке операции определены только над операндами совместимых типов. При обсуждении операций над вещественными данными уже затрагивались ошибки, связанные с совместимостью вещественных и целых типов. Аналогичные проблемы возникают при операциях над строками и символами и т.д. Далее будет дано более полное определение совместимости типов.
Два типа считаются совместимыми, если:
оба они есть один и тот же тип;
оба вещественные;
оба целые;
один тип есть тип-диапазон второго типа;
оба являются типами-диапазонами одного и того же базового типа;
оба являются множествами, составленными из элементов одного и того же базового типа;
оба являются строками одинаковой максимальной длины;
один тип есть тип-строка, а другой - тип-строка, упакованная строка или символ;
один тип есть любой указатель, а другой - нетипизированный указатель;
один тип есть указатель на объект, а другой - указатель на родственный ему объект;
оба есть процедурные типы с одинаковыми типом результата (для типа-функции), количеством параметров и типом взаимно соответствующих параметров.
Совместимость типов приобретает особое значение в операторах присваивания. Пусть 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.
Неявное преобразование типов возможно только в двух случаях:
в выражениях, составленных из вещественных и целочисленных переменных, последние автоматически преобразуются к вещественному типу, и все выражение в целом приобретает вещественный тип;
одна и та же область памяти попеременно трактуется как содержащая данные то одного, то другого типа (совмещение в памяти данных разного типа).
Совмещение данных в памяти может произойти при использовании записей с вариантными полями, типизированных указателей, содержащих одинаковый адрес, а также при явном размещении данных разного типа по одному и тому же абсолютному адресу. Для размещения переменной по нужному абсолютному адресу она описывается с последующей стандартной директивой ABSOLUTE, за которой помещается либо абсолютный адрес, либо идентификатор ранее определенной переменной. Абсолютный адрес указывается парой чисел типа WORD, разделенных двоеточием; первое число трактуется как сегмент, второе - как смещение адреса.
Неявные преобразования типов могут служить источником трудно обнаруживаемых ошибок в программе, поэтому везде, где это возможно, следует избегать их.