Назад Домой! Дальше Лекция 10_1. Структура адреса памяти в Turbo Pascal. Подпрограммы для работы с адресами.


Структура адресов памяти

Паскаль первоначально использовался на компьютерах с 16-битной адресной шиной. Максимальное 16-битное число = 65535. Чтобы расширить диапазон доступных адресов до 1Мб адрес разбивается на 2 части: старшую, называемую сегмент и младшую, называемую смещение. Максимальное значение каждой части = 65535 = $FFFF. Полный адрес вычисляется по формуле: сегмент*16 + смещение.

В Турбо Паскале принята такая структура распределения памяти: выделяется сегмент для кода (т е для команд откомпилированной программы.), обозначаемый CS. Адреса команд модуля имеют общий сегментный адрес и отличаются смещением (Offset). Поэтому размер откомпилированного модуля (в том числе - главной программы) не может превышать 64Кб. Аналогично, выделяется сегмент для данных (DS) и сегмент для стека (SP) (в стеке временно хранятся данные и код подпрограммы - на время ее исполнения)

Вы можете узнать сегментную часть адреса и смещение для элемента программы.
Программа, демонстрирующая работу с адресами:

type arab = array [1..10] of extended;
var xx,xx2: double; po1: ^double; w1: longint;
 zz : ^arab;
function kub(yy: double): double;
begin kub := sqr(yy)*yy;
writeln('yy : SEG= ',seg(yy),' OFS= ', Ofs(yy));
end;
begin
  write('Введи число -> '); readln(xx);
  xx2:= kub(xx);
  writeln('Число ',xx:0:1,' в кубе = ',xx2:0:1);
  writeln('----- Адреса: -----');
  writeln('xx : SEG= ',seg(xx),' OFS= ', Ofs(xx),' 1-й способ');
  writeln('xx2: SEG= ',seg(xx2),' OFS= ', Ofs(xx2));
  writeln('po1: SEG= ',seg(po1),' OFS= ', Ofs(po1));
  writeln('w1 : SEG= ',seg(w1),' OFS= ', Ofs(w1));
  writeln('zz : SEG= ',seg(zz),' OFS= ', Ofs(zz));
  writeln('kub: SEG= ',seg(kub),' OFS= ', Ofs(kub));
  po1 := @xx;
  w1:= longint(po1) shr 16;
  write('SEG_xx = ',w1,'   ');
  w1:= longint(po1) shl 16 shr 16;
  writeln('OFS_xx = ',w1,' - 2-й способ');
  new(po1); po1^ := kub(xx);
  writeln('po1^: SEG= ',seg(po1^),' OFS= ', Ofs(po1^));
  dispose(po1);
  new(zz); zz^[1]:= 2; zz^[2]:= 4.6;
  writeln('zz^[1]: SEG= ',seg(zz^[1]),' OFS= ', Ofs(zz^[1]));
  writeln('zz^[2]: SEG= ',seg(zz^[2]),' OFS= ', Ofs(zz^[2]));
  writeln('zz^[3]: SEG= ',seg(zz^[3]),' OFS= ', Ofs(zz^[3]));
  readln;
end.
---- Результаты работы: -----
Введи число -> 3
yy : SEG= 21692 OFS= 16372
Число 3.0 в кубе = 27.0
----- Адреса: -----
xx : SEG= 21647 OFS= 82 1-й способ
xx2: SEG= 21647 OFS= 90
po1: SEG= 21647 OFS= 98
w1 : SEG= 21647 OFS= 102
zz : SEG= 21647 OFS= 106
kub: SEG= 21160 OFS= 18
SEG_xx = 21647   OFS_xx = 82 - 2-й способ
yy : SEG= 21692 OFS= 16372
po1^: SEG= 22716 OFS= 0
zz^[1]: SEG= 22716 OFS= 0
zz^[2]: SEG= 22716 OFS= 10
zz^[3]: SEG= 22716 OFS= 20

Выводы:

1. Адрес сегмента данных (DS) = 21647.
2. Так как данные типа double занимают 8 байт, а OFS= 82, 90, 98 - для xx, xx2, po1 то объявленные переменные расположены в памяти последовательно, вплотную друг за другом.
3. Адрес сегмента стека (SP) = 21692. Данные в стеке расположены от старших адресов к младшим, для yy OFS = 16372, следовательно, таков примерно объем стека (это - настройка среды, можно изменить).
4. Адрес сегмента "кучи" = 22716
5. Так как память была освобождена от po1^, zz^[1] расположен по этому же адресу (OFS = 0).
6. Элементы массива zz^ расположены вплотную друг за другом (размер данных типа extended = 10б)

Подпрограммы

Справки о подпрограммах получены копированием из справочной системы Turbo Pascal (автор русской версии - студент МГТУ им. Баумана Шепель Олег Борисович, известный в Internet как VideoLord. Версия файла = 1.1r, дата последнего изменения = 09.02.99)

Процедура-функция New

Создает новую динамическую переменную и устанавливает на нее указатель.
  Объявление:
  Procedure New(Var P : Pointer [, Init : Constructor ]);
  Замечания:
Объявление New было расширено, так что теперь она может также инициализировать объект распределенный в куче, если вы передаете конструктор этого объекта как второй параметр, например:
New(T, Init(360, 174));
Также, обявление New было расширено, чтобы действовать как функция, возвращающая значение указателя. Подробнее - см справочную систему.

Процедура Dispose

Освобождает место, занятое динамической переменной в памяти.
  Объявление:
  Procedure Dispose(Var P : Pointer [ , Destructor ]);
Объявление процедуры Dispose, было расширено так, что теперь она может также освобождать память занятую объектом, распределенным в куче, если вы передаете деструктор этого объекта как второй параметр, например:
Dispose(P, Done);
После обращения к Dispose, значение указателя P становится неопределенным и ссылаться на него является ошибкой.

Процедура GetMem

Создает динамическую переменную определенного размера и записывает ее адрес в памяти в указательную переменную.
 Объявление:
 Procedure GetMem(Var P : Pointer; Size : Word);
 Замечания:
Параметр P - переменная любого указательного типа. Параметр Size - выражение, определяющее размер динамической переменной в байтах. Недавно созданная переменная может быть вызвана как P^.

Если в куче недостаточно свободного пространства для распределения динамической переменной, то происходит ошибка во время выполнения программы.
Ограничения:
Самый большой блок, который может быть безопасно распределен в куче равен 65,528 байт (64K-$8).

Процедура FreeMem

Освобождает память, занятую динамической переменной данного размера.
 Объявление:
 Procedure FreeMem(Var P : Pointer; Size : Word);
 Замечания:
Параметр P - переменная любого указательного типа, предварительно распределенная в памяти процедурой GetMem или та, которой было присвоено значение оператором присваивания.
Параметр Size - выражение, определяющее размер динамической переменной в байтах, память, занимаемую которой нужно освободить. Он должен быть равен числу байт, предварительно распределенных для этой переменной процедурой GetMem.
Процедура FreeMem уничтожает переменную, связанную с P и освобождает память, занимаемую этой переменной. Если P не указывает на область памяти в куче, то происходит ошибка во время выполнения программы. После обращения к FreeMem, значение P становится неопределенным и если вы впоследствии пытаетесь сослаться на P^, то происходит ошибка.

Функция Seg

Возвращает сегмент определенного объекта.
 Объявление:
 Function Seg(X) : Word;
 Замечания:
Параметр X - любая переменная или идентификатор процедуры или функции. Результат типа Word, является сегментной частью адреса X.

Функция Ofs

Возвращает смещение определенного объекта.
 Объявление:
 Function Ofs(X) : Word;
 Замечания:
Параметр X - это любая переменная или идентификатор процедуры или функции. Результат типа Word - смещение адреса X в памяти.

Процедура Move

Копирует байты из Source в Dest.
 Объявление:
 Procedure Move(Var Source, Dest; Count : Word);
 Замечания:
Копирует определенное число байт (Count) из Source в Dest. Никакая проверка диапазона не выполняется. Всегда, когда возможно, используйте SizeOf, чтобы определять количество копируемых байтов.

Процедура FillChar

Заполняет определенное количество (Count) непрерывных байт определенным значением (типа Byte или Char).
 Объявление:
 Procedure FillChar(Var X; Count : Word; Value);
 Замечания:
 X     - буфер, который нужно заполнить
 Count - количество символов
 Value - заполнитель (типа Byte или Char)
Не выполняет проверки диапазона.

Функция Addr

Возвращает адрес определенного объекта.
 Объявление:
 Function Addr(X) : Pointer;
 Замечания:
Параметр X - идентификатор переменной, процедуры или функции. Результат - указатель на X. Как и NIL, результат функции Addr совместим со всеми типами указателей.

Оператор @

Аналогично Addr - возвращает адрес определенного объекта. Например: pp:=@xx;
(Указатель pp получает значение адреса переменной xx).

Функция CSeg

Возвращает текущее значение регистра CS.
 Объявление:
 Function CSeg : Word;
 Замечания:
Результат типа Word - сегментная часть адреса сегмента кода, в котором была вызвана функция CSeg.

Функция DSeg

Возвращает текущее значение регистра DS.
 Объявление:
 Function DSeg : Word;
 Замечания:
Результат типа Word - сегментная часть адреса сегмента данных.

Функция SSeg

Возвращает текущее значение регистра SS.
 Объявление:
 Function SSeg : Word;
 Замечания:
Результат типа Word является сегментной частью адреса сегмента стека.

Функция SPtr

Возвращает текущее значение регистра SP.
 Объявление:
 Function SPtr : Word;
 Замечания:
Возвращает смещение указателя на вершину стека внутри сегмента стека.

Функция MemAvail

Возвращает количество всей свободной памяти в куче.
 Объявление:
 Function MemAvail : Longint;
 Замечания:
MemAvail возвращает сумму размеров всех свободных блоков в куче. Обратите внимание, что непрерывный блок памяти возвращенного размера, вряд ли будет доступен из-за фрагментации кучи. Чтобы найти самый большой свободный блок, вызовите MaxAvail.

Функция MaxAvail

Возвращает размер самого большого непрерывного свободного блока в куче.
  Объявление:
  Function MaxAvail : Longint;
  Замечания:
 Возвращает больший из:
  - Самых больших свободных блоков внутри области менеджера
    управления динамической памятью
  - Глобальной кучи Windows
Значение соответствует размеру самой большой динамической переменной, которая может быть распределена.

Функция Ptr

Преобразовывает адрес в виде сегмент:смещение в указатель.
 Объявление:
 Function Ptr(Seg, Ofs : Word) : Pointer;
 Замечания:
Seg и Ofs - выражения типа Word. 
Результат - указатель, показывающий на
адрес Seg:Ofs. Результат, возвращаемый Ptr,
совместим со всеми типами
указателей (как и NIL).

Например:

 If Byte(Ptr($40, $49)^) = 7 Then WriteLn('Видеорежим - монохром');

Пример: Решение системы уравнений. Используем указатели

Назад Дальше
Rambler's Top100
Hosted by uCoz