[an error occurred while processing this directive]
.сс
8 Внутренние форматы
_______________________________________________________________
Любая версия Паскаля имеет свои, характерные для нее размеры переменных, перечисляемых типов и т.д. В этой главе приводится информация о структурах данных СП "Паскаль". Эта информация будет полезна тем, кто использует в программах на Паскале машинные подпрограммы (см. раздел 5.8 и главу 9).
8.1 Размеры и диапазоны простых типов
Следующая таблица содержит информацию о количестве байт в переменной каждого простого типа, а также диапазон значений, принмаемых переменной:
ТипМинимальноеМаксимальноеРазмер значениезначениевбайтах char02551 boolean011 integer-214748364821474836474 real-1.70141183E381.70141183E385 set0..00..25532 перечисляемый02551 указатель0655352 файл--5+элементы
8.1.1 Символьный тип
Использование символьного типа в СП "Паскаль" осуществляется стандартным образом. Единственная особенность сивольного типа в данной реализации заключается в том, что сивол chr(128) используется в качестве указателя конца читаемого файла при выполнении операторов 'read', 'readln' или 'get(input)'. С клавиатуры этот код можно получить, нажав f0''. Размер символа, естественно, один байт.
8.1.2 Логический тип
Логические костанты 'false' и 'true' имеют обычные значения 0 и 1 соответственно (как требует стандарт), таким образом выражение 'false<true' истинно. В памяти они хранятся как одиночные байты.
8.1.3 Целый тип
Целые числа имеют длину 4 байта, что позволяет использовать диапазон от -2^31 до +2^31-1. Константа 'maxint' имеет значение 2147483647. В памяти и файлах целое число хранится в порядке возрастания значимости байтов.
.сс
8.1.4 Вещественный тип
Вещественные числа хранятся в пяти байтах: один байт экспоненты плюс четыре байта мантиссы. Экспонента хранится в форме 'значение+128'. Четыре байта мантиссы располагаются в порядке убывания значимости. Седьмой бит первого байта мантиссы - знак для всего числа: 0 - положительное, 1 - отрицательное число. Вещественные числа нормализованы таким образом, что в двоичной нотации {.1} стоит перед старшим значащим битом мантиссы. Следующая диаграмма помогает лучше понять это:
.ми0
эксп.мантисса 1м2м3м4 +---++--------------++---++---++---+ |&82||0{.1}1000000||&00||&00||&00| +---++--------------++---++---++---+ ^^ Экспонента=||Мантисса = 0.11 двоичное &82-&80=2||т.о. число = .11*2^2=11 ||что = 3 десятичному || ||Подразумевается как |наличие первого знака мантиссы | Знаковый бит = 0, т.о. число положительное
.нф
Здесь показано, как вещественное число 3 представляется последовательностью байт &82, &40, &00, &00, &00.
8.1.5 Тип 'SET'
Хотя тип SET не является простым, он имеет стандартную внутреннюю форму, и поэтому рассматривается в этом разделе. Данный тип имеет длину 32 байта (256 бит). Таким образом множество может включать до 256 элементов, по одному биту на каждый. Границы множества должны находится внутри диапазона 0..255, например:
type set1 = set of char; {ordinal values 0..255} colour = (red,green,blue); set2 = set of colour; {ordinal values 0..2} set3 = set of 50..150; {ordinal values 50..150} set4 = set of 'A'..'Z'; {ordinal values 65..90}
Следующие примеры не удовлетворяют условию соблюдения границ множества:
type set5 = set of integer; {ordinal values -maxint-1..maxint} set6 = set -1..254 {ordinal values -1..254}
Важным свойством данной реализации Паскаля является возможность использования символьных множеств, так как это бывает нужно довольно часто. В памяти, 0-й бит первого байта указывает на наличие или отсутствие 0-го элемента множества, а 7-й бит последнего байта - 255-го элемента множества.
8.1.6 Перечисляемый тип
Элементы перечисляемого типа имеют однобайтную форму. Первый элемент в определении типа имеет значение '0', второй - '1', и т.д. до '255'. Таким образом, максимальный размер перечисляемого типа равен 256, что вполне достаточно для большинства применений.
8.1.7 Тип указателей
Указатели имеют длину два байта. Их содержимое прямо не используется непосредственно. Адрес, хранящийся в указателе указывает на первый байт кааого либо объекта в памяти машины. Эти объекты распологаются в рабочей области.
8.2 Сложные типы
Массивы, файлы, записи и множества создаются на основе простых типов. Множества были рассмотрены выше, поэтому дальше о них не упоминается. Сложные типы могут быть объявлены 'упакованными'. В данной реализации Паскаля упаковка применима только двум следующим целым поддиапазонам:
мин..макс, где 0<мин<=255 и мин<=макс<=255 хранится как один байт, и
мин..макс, где 0<=мин<=65535 и мин<=макс<=65535 хранится как два байта.
Например:
type byte = 0..255; word = 0..65535; {256 one-byte elements} codes = packed array[byte] of byte; {10 two-byte elements} addrs = packed array[1..10] of word; brkp = packed record locn : word;{2 bytes} val : byte{1 byte} end;
Попытка упаковать структуры, диапазон значений которых не удовлетворяет предыдущему правилу, не приведет к положительному результату. Например:
type big = packed array[1..10] of -100..0;
Хотя относительный диапазон значений элементов массива равен 101, их внутренняя форма хранения останется равной четырем байтам, так как нижняя граница диапазона меньше ноля, что противоречит условию упаковымаемости типа.
8.2.1 Массивы
Элементы массивов располагаются в памяти последовательно, первый элемент хранится с начала области массива. Рассмотрим простой массив:
var simpleArray : array[1..10] of integer;
Первый элемент массива simleArray[1] занимает первые четыре байта, второй - следующие четыре, и т.д. Таким образом, весь массив занимает сорок байт.
А теперь более сложный пример:
var textArray : packed array[1..9,1..8] of char;
это эквивалентно описанию:
var textArray : packed array[1..9] of packed array[1..8] of char;
из которого видно, что массив состит из девяти строк, по восемь символов в каждой. Они хранятся в следующем порядке:
.ми0
Память ---> +----------+----------++----------+ |1-я строка|2-я строка| ... |9-я строка| +----------+----------++----------+ .нф 111111112222222299999999 123456781234567812345678
Общий объем памяти, требуемой для хранения массива можно определить так. Предположим объявлен n-мерный массив:
var eg : array[low1..high1,low2..high2, ... lown..highn] of t;
Требуемое количество байт равно:
(high1-low1+1)*(high2-low2+1)* ... (highn-lown+1)*size(t)
где size(t) - размер одного элемента массива. Для символьного массива, описанного ранее, размер будет равен:
(9-1+1)*(8-1+1)*size(char) = 9*7*1 = 63 байта
В другом примере:
var anArray : packed array[-10..9,20..30} of 1..31;
соответствующие вычисления дают ответ:
(9-(-10)+1)*(30-20+1)*size(1..31) = 20*11*1 = 220 байт
Обратите внимание, что size(1..31) равно еденице, так как массив упакован. В противном случае size(1..31) было бы равно четырем.
8.2.2 Записи
Структура конкретной записи зависит от совокупности типов ее компонент. Так как запись может быть упакована, входящие в нее целочисленные диапазоны могут занимать по 1, 2 или 4 байта. Расммотрим описание типа:
type rec = record x,y : 0..99; name : packed array[1..10] of char; shape : (circle, ellipse, square) end;
Общая длина описанной струтуры составляет 19 байт. Первые четыре - поле 'x'; следующие четыре - поле 'y'; следующие десять - поле 'name'; и последний байт - поле 'shape'.
Если бы запись была упакована, поля 'x' и 'y' занимали бы по одному байту, а суммарная длина записи равнялась бы 13 байтам.
8.2.3 Файлы
Файлы объявляются в заголовке программы, а также в ее описательной части. Исключение составляют файлы 'input' и 'output', которые упоминаются только в заголовке, и временные файлы, определяемые в процедурах и функциях.
Условие упаковки массивов распространяется и на файлы. Порядок размещения данных в файле аналогичен размещению в памяти. Следовательно, файл, объявленный таким образом:
type recFile = file of rec; {rec defined above}
будет содержать записи длиной 19 байт, организованные так, как описано выше. Заметьте, что описание:
type recFile = packed file of rec;
не приведет к уменьшению размеров записей, упаковку надо было делать при описании типа 'rec'.
Файлы состоят из двух частей: 5-ти байтный описатель файла и буфер данных. Если используется функция 'code1' для доступа к файлу, часть файловой переменной, содержащая регистры XY, при вызове функции:
res := code1(addr,1,myFile);
должна содержать адрес описателя файла, а вызов функции вида:
res := code1(addr,1,myFile^);
Позволяет обратиться к буферу данных файла, так как его адрес будет помещен в регисты XY при вызове последней функции.
Формат описателя файла следующий:
.ао0
XY+m+----------------------------------------------+} ||} |Буфер данных|} n байт ||} XY+5+----------------------------------------------+} |Флаги|1 байт XY+4+----------------------------------------------+ |Указатель файла в ОС|1 байт XY+3+----------------------------------------------+ |Размер компоненты (старший байт)|} XY+2+----------------------------------------------+}2 байта |Размер компоненты (младший байт)|} XY+1+----------------------------------------------+ |Внутренний номер файла|1 байт XY+0+----------------------------------------------+
.нф
Внутренний номер равен нулю для постоянных файлов (чьи имена указаны в заголовке программы), и 1-8 для временных файлов. Если внутренний номер файла равен n, его имя будет: 'pas___m', где m равно n-1. Таким образом, первый временный файл будет иметь внутренний номер 1 и имя 'pas___0'.
Размер компоненты - это двухбайтовая величина, содержащая размер одного элемента, из которых состоит файл. Так, для файла, содержащего целые числа, размер компоненты будет равен четырем, а файл, содержащий упакованные логические массивы 'packed array[1..100] of boolean', будет иметь размер компоненты, равный 100. Одновременно, это размер буфера данных, расположенного за описатаелем файла.
Указатель файла в файловой системе - это номер, присваемый файлу операционной системой при его открытии. Его значение зависит от того, сколько файлов было уже открыто, и какие были закрыты.
Флаги хранятся в одном байте, два бита в котором не используется:
бит0не используется бит1не используется бит2'1', если в качестве файла используется консоль. бит3'1', если файловой системой установлен флаг EOF. бит4'1', если истинна функция eof Паскаля. бит5'1', если значение eoln истинно. бит6'1', если буфер данных файла содержит данные. бит7'1', если файл читается, '0', если пишется.
Формат буфера данных полностью совпадает с форматом его компоненты.
8.2.4 Текстовые файлы
Текстовые файлы обладают специфическими особенностями. Хотя это просто 'file of char', с ними можно обмениваться не только символами, но и другими данными. В дополнение к символам, целые и вещественные числа могут помещаться и читаться из текстовых файлов, а логические значения и строки могут запиываться в них. Разные типы данных имеют в тестовых файлах следующее представление:
Char:cгде, 'c' - символ String:cccccгде, 'c' столько, сколько символов в строке Integer:iiiiiiiiiiiiгде, 'i' - цифры, составляющие число или пробел(ы) перед ним Real:ddddddddddddгде, 'd' - цифра, '+', '-', 'е' или пробел(ы) перед числом Boolean:'FALSE' или 'TRUE'
Таким образом, для текстовых файлов имеются стандартные размеры компонент: 1, длина строки, 12, 12 и 5 для символов, строк, целых, вещественных чисел и логических констант соответственно. Общая печатаемая ширина и количество цифр после запятой (для вещественных значений) может быть изменена установкой формата печати в операторе 'write' (и 'writeln'), например:
write(123 : 4); write(1.23 : 6 :3); write(1<>2 : 7) write(' ' : 40); write('Number of eggs:' : 34);
Конечно, вместо константы, ширину печати может задавать выражение. Максимально допустимая ширина печати и максимальное число цифр после запятой равны 255 и 48 соответственно.
При чтении из текстовых файлов, могут использоваться только символы, вещественные и целые числа. Числа должны разделяться пробелами или переводами строк.
.ст pascal.9
[an error occurred while processing this directive]