CSeg : Word -- Содержимое регистра CS процессора
DSeg : Word -- Содержимое регистра DS процессора
SSeg : Word -- Содержимое регистра SS процессора
SPtr : Word -- Содержимое регистра SP процессора
При работе программы ее текущий исполнимый код находится в кодовом сегменте, что фиксируется в регистре CS, а статические переменные основного блока и типизированные константы располагаются в сегменте данных, который запоминается регистром DS. Локальные переменные и параметры процедур и функций при вычислениях располагаются в стеке, и сегмент стека содержится в регистре SS. Последний регистр – SP – содержит смещение указателя стека в сегменте SSeg.
10.4. Тип Pointer
В Турбо Паскале предопределен специальный адресный тип Pointer — указатель: можно объявлять переменные, значением которых будет адрес ячейки памяти:
VAR
Р : Pointer; { переменная-указатель }
Значения этого типа занимают 4 байта памяти и содержат адрес какой-либо ячейки памяти. Адрес хранится как два слова: одно из них определяет сегмент, а другое — смещение. Значение указателя не может быть в явном виде выведено на экран или печать. Его надо предварительно расшифровывать. Для работы с указателями
- 190 -
вводится специальный набор функций. Кроме того, указатели полностью совместимы со ссылочным типом и могут использоваться (с оговорками) как ссылки. Указатели могут обмениваться значениями через оператор присваивания (:=), и сравниваться операторами = и <>. Но сравнение их — весьма ненадежная операция. Так, когда два указателя содержат один и тот же адрес в памяти, но записанный в них разными способами, они считаются различными. Таким образом, два указателя считаются одинаковыми, если в них записаны одинаковые значения сегмента и смещения. Во всех остальных случаях они считаются неравными. Понятия «больше» и «меньше» к значениям типа Pointer неприменимы.
Если мы хотим указать в программе на значение по указанному в переменной типа Pointer адресу, то мы должны использовать символ «^» после имени указателя, например: Р^. Это есть операция разыменования. Подробно этот вопрос рассмотрен при описании работы со ссылками, а особенности разыменования указателей обсуждаются вместе с работой функции Ptr.
10.5. Средства для работы с адресами
В разд. 10.3 были рассмотрены средства анализа расположения частей работающей программы. Обсудим инструментарий, применимый к данным, используемых программой. Это операции достаточно низкого уровня, но некоторые из рассматриваемых здесь функций можно с успехом применять и на более высоком уровне, в частности при работе с ссылками и динамическими данными. Список таких функций приведен в табл. 10.2.
Таблица 10.2
Функция : Тип -- Возвращаемое значение
Addr(X) : Pointer -- Ссылка на начало объекта X в памяти
Seg(X) : Word -- Сегмент, в котором хранится объект X
Ofs(X) : Word -- Смещение в сегменте для объекта X
Prt(S, O : Word) : Pointer -- Ссылка на место в памяти, заданное значениями смещения O и сегмента S
SizeOf(X) : Word -- Размер объекта X в байтах
Операция @X : Pointer -- Возвращает ссылку на начало объекта X памяти (аналог функции Addr)
10.5.1. Определение адреса переменных
Функции Addr(X), Seg(X) и Ofs(X), а также оператор @ возвращают адрес объекта X или компоненты адреса. Под X можно понимать любой объект: переменные любых типов, объекты, процедуры и функции (но не константы).
Функция Addr(X) и оператор @ возвращают значение типа Pointer — адрес объекта X. Их действие одинаково:
VAR
X : String; p, q : Pointer;
...
р: = Addr( X );
q: = @X;
{Теперь p=q, и адреса равны; они указывают на один объект }
Значение типа Pointer не может быть выведено на экран. Но так как этот тип состоит из двух слов (Word), хранящих сегмент и смещение, можно вывести их в отдельности, используя функции Seg и Ofs (обе типа Word):
WriteLn( 'Сегмент ', Seg( р ), ' смещение ', Ofs( р ));
В то же время значения ссылок можно получить в режиме отладки. Они будут выводиться в окна наблюдения и модификации (Watch и Evaluate).
Может возникнуть вопрос — а зачем вообще нужна функция Addr, если есть Seg и Ofs, тем более что нельзя распечатать ее значение? Ответ: функция Addr и оператор @ нужны для привязывания ссылок, т.е. динамических переменных, к статическим данным, а также для работы с массивами данных в виде OBJ-файлов, связанных с выполнимым файлом на этапе компоновки. Пример компоновки внешних данных дан при описании работы с образом экрана на диске в разд. 20.4 «Работа с образом экрана на диске».
Заметим, что если P — ссылка, то Addr(P) или @P, а также Seg(P) и Ofs(P) вернут адрес или сегмент со смещением самой переменной-ссылки P в области статических данных, но Addr(P^) или @Р^ и Seg(P^) с Ofs(P^) возвратят содержимое ссылки P, т.е.
Р = Addr( Р^).