размером 12 байт (6+6), то его размер необходимо увеличить еще на 4 байта. Для этого вместо приведенного выше описания необходимо дать следующее:

TYPE

Dot = RECORD

х, у : Real;

foo : Array [1..4] of Byte

END;

Теперь при размещении переменной типа Dot память будет выделяться и, что самое главное, освобождаться блоками по 16 байт. Заметим, что в принципе можно было бы отказаться от использования процедур New и Dispose и управлять памятью с помощью одних лишь процедур GetMem и FreeMem, хотя это вызвало бы определенные трудности при работе с объектами.

<p>11.5.6. Обработка ошибок распределения памяти</p>

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

FUNCTION ИмяФункции( Size : Word ) : Integer;

- 210 -

Обычно ее называют HeapFunc. Эта функция вызывается в случае, когда New или GetMem не может обработать запрос на распределение кучи. Параметр Size содержит размер блока, который не мог быть распределен, и функция обработки ошибки должна попытаться освободить блок размером не меньше Size. В качестве результата функция должна возвращать значения 0, 1 или 2. В случае 0 немедленно будет возникать фатальная ошибка и останов программы. В случае 1 вместо аварийного завершения процедуры New или GetMem будет возвращаться указатель, равный nil. Наконец, 2 означает как бы замалчивание ошибки, но вызывает повторение запроса на распределение, что, впрочем, может опять вызвать ошибку.

Необходимо, чтобы эта функция компилировалась в режиме {$F+}. Функция обработки ошибки (пусть в программе она названа UserHeapFunc) может быть подставлена в монитор кучи присваиванием ее адреса системной переменной HeapError:

HeapError := @UserHeapFunc;

Мало смысла в том, чтобы писать свои функции HeapFunc, возвращающие значение 0. Программа и так оборвется при нехватке памяти в куче. Зато очень удобно обрабатывать ошибки распределения памяти, если установить возвращаемое значение равным 1:

{$F+}

FUNCTION HeapFunc(Size : Word) : Integer;

BEGIN

HeapFunc := 1

END;

{$F-}

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

...

New(P);

if P = nil then обработка ситуации нехватки памяти;

{иначе нормальная работа с P^}

...

Если пойти еще дальше, то можно написать функцию HeapFunc такой структуры:

- 211 -

($F+}

FUNCTION HeapFunc( Size : Word ) : Integer;

BEGIN

{ ОСВОБОЖДЕНИЕ КАКИМ-ЛИБО СПОСОБОМ Size БАЙТ В КУЧЕ }

HeapFunc := 2 {и повтор неудачного распределения }

END;

{$F-}

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

<p>11.6. Ссылки, работающие не с кучей</p>

Традиционно понятие «ссылка» всегда увязывается с динамическими переменными, кучей и т.п. У Турбо Паскаля тоже есть традиции. Одна из них — расширение общепринятых стандартов. В частности, ничто, кроме традиционных учебников стандартного Паскаля, не обязывает связывать ссылки или указатели именно с кучей. Ссылки могут указывать на что угодно: даже на выполнимый код программы (крайний и бесполезный случай). Обычно в разных трюках ссылки связываются со статическими данными или с системными областями памяти ПЭВМ (областью данных БСВВ, видеопамятью и др.).

Кроме способа связывания, такие ссылки ничем не отличаются от рассмотренных ранее (рис. 11.8).

| PROGRAM NoHeap;

| { ПРИМЕР ССЫЛОК БЕЗ ИСПОЛЬЗОВАНИЯ КУЧИ }

| TYPE { базовые типы: }

| VideoArray=Array[1..4000] of RECORD {структура экрана }

| Symbol : Char;

| Attrib : Byte

| END;

| Vector=Array[1..100] of Real; { одномерный массив }

| Matrix=Array[1..10,1..10] of Real;{ матрица 10 на 10 }

| VAR

| VideoPtr : ^VideoArray; { ссылка на структуру экрана }

| Vec : Vector; { ссылка на одномерный массив }

| MatPtr : ^Matrix; { ссылка на массив — матрицу }

| P : Pointer; { просто указатель }

| i : Word; { счетчик для циклов }

Рис. 11.8

- 212 -

| BEGIN

| VideoPtr := Ptr( $B800, 0 );

{Переменная VideoPtr теперь содержит адрес начала видеопамяти в цветных и черно-белых режимах. Для режима mono надо подставить в присваивании Ptr{$B000,0). После этого можно непосредственно обращаться к видеопамяти. }

| for i:=1 to 4000 do begin

| { Заполнение видеопамяти}

Перейти на страницу:

Поиск

Похожие книги