Основы программирования (947332), страница 37
Текст из файла (страница 37)
Для обращения к конкретному байту необходимо знатьего номер, который называют его физическим адресом.Память принято делить на слова, двойные слова и параграфы. Словоимеет длину 2 байта, двойное слово ~ 4 байта, а параграф - 16 байт.При работе с памятью используется адресация по схеме «база + смещение» (рис. 7.1). При этом адрес конкретного байта М определяется как адреснекоторого заданного байта А5 (адрес базы) + расстояние до требуемого байта AQ^ (смещение),2127. Программированиес использованием динамической памятиВ микропроцессорах фирмы Intel(начиная с i8086) в качестве адреса базыиспользуют адреса, кратные 16.
Четыре 0 1 2 3 4 5последних бита такого адреса равны О, иМих не хранят, а аппаратно добавляют привычислении физического адреса.Рис. 7.1. Адресация по схемеНепрерывный участок памяти, име«База + смещение»ющий длину не более 64 КБ и начинающийся с адреса, кратного 16 (0,16,32, ), называют сегментом. Адрес начала сегмента принимают за базу для всего сегмента. Адрес базы сегмента безпоследних четырех бит называют сегментным.Сегментный адрес и смещение имеют размер по 16 бит (слово). Физический адрес, получаемый при их сложении с учетом отброшенных четырехбит (рис.
7.2), имеет размер 20 бит и может адресовать память объемом 2^^байт или 1 МБ.Максимальное смещение равно 2^^-1, что соответствует 64 КБ памяти.Таким образом, относительно одной базы можно адресовать не более 64 КБпамяти, что ограничивает размер сегмента.Примечание. Современные модели микропроцессоров используют адреса большей длины с отличающейся схемой получения физического адреса, что учитывается версиями Pascal,предназначенным для работы «под Windows», но принцип адресации по схеме «база+смещение» используется и там.Программа и данные хранятся в памяти фрагментами, каждый из которых расположен в своем сегменте. Различают три вида сегментов: кодов,данных и стека. В сегментах кодов хранится собственно программа.
В сегментах данных размещаются глобальные переменные и константы. Сегментстека интенсивно используется в процессе выполнения программы: при вызове подпрограмм в стек записывается адрес возврата, в нем размещаютсялокальные переменные, копии параметров-значений, адреса параметров-переменных и параметров-констант и т.п. (см. фрейм активации в параграфе 5.6).В процессе работы сегментные адреса хранятся в специальных сегментных регистрах:16 битCS - адрес базы сегмента кодов;DS - адрес базы сегмента данных;SS - адрес базы сегмента стека.Сегментный адрес+0000СмещениеФизический адресДоступ к конкретным участкам сегмента осуществляется черезсоответствующие смещения.20 битРис.
7.2. Получение физического адреса213Часть 1. Основы алгоритмизации и процедурное программированиеПри записи адреса в память отдельно сохраняются сегментный адрес и смещение(рис. 7.3).В Borland Pascal для работы с адресами используется специальный тип данных - указатель. Данные этого типа включают два поля типа word и хранят соответственно сегментныйСегментныйСмещениеадрес2 байта2 байтаРис. 7.3. Структуразаписи адреса в памятьадрес и смещение.Различают указатели двух типов: типизированные и нетипизированные.Типизированные указатели содержат адреса, по которым в памяти размещаются данные определенных типов. Используя эти указатели с даннымиуказанных типов, можно выполнять операции, предусмотренные базовымтипом.
Синтаксическая диаграмма объявления типизированного указателяприведена на рис. 7.4.Например:Туре tpi=4nteget;Varpi.tpi;{объявляем тип «указатель на целое»}{объявляем переменную этого типа}или без предварительного объявления типа:Varpi: ^integer; {объявляем переменную типа «указатель на целое»}Нетипизированные указатели хранят просто адреса, которые не связаны с данными конкретных типов. Для их объявления используют зарезервированное слово pointer. Например:Varр:pointer;...Указатели - единственное исключение из общего правила, согласно которому все ресурсы перед использованием должны быть описаны.
Для нихдопускаются описания вида:Турерр = ^регсоп;{тип person еще не определен!}регсоп = record{определение типа person}пате: string:next: рр;end;...-<АИдентификаторбазового типаРис. 7.4. Синтаксическаядиаграмма <Объявлениетипизированного указателя>214Для указателей, которые не хранят никаких адресов, введена константа «нулевойадрес» с именем nil. Константу nil можноприсваивать указателю любого типа.Инициализация указателей. Для объявления инициализированных указателейиспользуют типизированные константы, но7. Программирование с использованием динамической памятиединственное значение, которое может быть присвоено указателю при инициализации - это значение nil.
Например:Constp:^real=nil;...Операции над указателями. Над значениями указателей возможныследующие операции.Присваивание, При выполнении этой операции указателю присваивается значение другого указателя или nil. Допускается присваивать указателютолько значение того же или неопределенного типа.Например:Varр1, р2: ^integer;рЗ: ^real;р: pointer;{допустимые операции}pJ:=p2; р:=рЗ; р1:=р; pl:=nil; р:=пП;(недопустимые операции}рЗ:=р2; pJ:=p3;,..Получение адреса.
Это унарная операция, которая строится из знакаоперации - символа @ (коммерческое а) и одного операнда - переменнойлюбого типа. Результат операции - указатель типа pointer, который можноприсвоить любому указателю.Например:Var i.integer;pi: ^integer;...pi:=@i; {указатель pi будет содержать адрес переменной i}Доступ к данным по указателю (операция разыменования). Чтобы получить доступ к переменной по указателю, необходимо после переменной типизированного указателя поставить знак «'^».
Полученное значение имееттип, совпадающий с базовым типом указателя. Нетипизированные указателиразыменовывать нельзя.Например:j:=pi^; {переменной] присваивается значение целого, расположенного по адресу pi}pi^:=pi^-^2; {целое значение, расположенное по адресу pi, увеличивается на 2}В табл. 7.1 показано, как выполняются операции с указателями.215Часть 1. Основы алгоритмизации и процедурное программированиеТ а б л и ц а 1ЛРезультатоперацииФрагментпрограммыОписание операцииpiConst i:integer=];Var pi: ^integer;Т 11?^1 ^ 1Создается инициализированнаяпеременная i и указатель на целое pipi\1pi:=@i;N'1pi^:^pi^j^2;Указателю pi присваивается адрес переменной i1 1pi\1\ .Значение, адрес которого находится в pi, увеличивается на 21 3 1pi:-nil;pi0 1\|Запись в pi константы «нулевойадрес»I ^1Операции отношения.
Из всех возможных операций отношения допускаются только операции проверки равенства (=) и неравенства (< >). Этиоперации проверяют соответственно равенство и неравенство адресов. Например:sign:=pl=p2; {переменная sign логического типа получает значениеtrue или false в зависимости от значений указателей}илиifplonilthen ... {проверка адреса}Поскольку в качестве базового типа типизированного указателя можетбыть использован любой тип, допустимо определять «указатель на указатель». Например, если переменную ppi описать и инициализировать следующим образом:2167.
Программирование с использованием динамической памятиConst i:integer^ 1;Var pi: integer;ppi: ""pi;ppi\\pipi:=@i;ppi:=@pi; ...\\i1Рис. 7.5. Указатель науказательTO будет реализована схема, изображенная нарис. 7.5.Для получения значения переменной i необходимо дважды применить операцию разыменования. В нашем случае ppi^^ имеет типinteger и равно 1.Процедуры и функции, работающие с указателями. Для работы суказателями в Паскале предусмотрены стандартные функции, облегчающиеи упрощающие выполнение часто встречающихся операций.1.
Функция ADDR(x): pointer - возвращает адрес объекта х, в качествекоторого может быть указано имя переменной, функции, процедуры. Выполняет те же действия, что и операция «@».2. Функция SEG(x): word - возвращает сегментный адрес указанногообъекта.3. Функция OFS(x): word- возвращает смещение указанного объекта.4. Функция CSEG: word- возвращает текущее значение сегментного регистра CS - сегментный адрес сегмента кодов.5. Функция DSEG: word- возвращает текущее значение сегментного регистра DS - сегментный адрес сегмента данных.6. Функция PTR(seg,ofs:word):pointer - возвращает значение указателяпо заданным сегментному адресу seg и смещению ofs.Преобразование типов данных с использованием типизированныхуказателей.
Как отмечалось ранее, типизированный указатель связываетсяс некоторым типом данных и адресует вполне определенную область памяти, соответствующую длине внутреннего представления своего типа. Еслиуказателям разного типа присвоить один и тот же адрес, то каждый из них будет рассматривать содержимое области в соответствии с внутренним представлением своего типа. Эта особенность указателей позволяет использоватьих для неявного преобразования типа.Необходимо помнить, что для присвоения разнотипным указателям одного и того же адреса следует использовать нетипизированные указатели, либо задавать абсолютное значение требуемого адреса.Например:Var L:longint;{длинное целое число}Р1:^аггау[1..4] of byte; {указатель на область длиной 4 байта}k:byte;217Часть J.