



                          ГЛАВА 4

                         Переменные

                    Описания переменных

     Описание переменной представляет собой список идентифи-
каторов, которые обозначают новые переменные и их типы.

            -----------    -    -----                     -
описание--->!список   !-->(:)-->!тип!------------------->(;)-->
переменной  !идентифи-!    -    ----- !                ^  -
            !каторов  !               !  ------------- !
            -----------               -->!абсолютное !--
                                         !предложение!
                                         -------------

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

var
  X,Y,Z: real;
  I,J,K: integer;
  Digit: 0..9;
  C: Color;

                                - 2 -


  Done,Error: boolean;
  Operator: (plus, minus, times);
  Hue1,Hue2: set of Color;
  Today: Date;
  Results: MeasureList;
  P1,P2: Person;
  Matrix: aaray[1..10,1..10] of real;

     Переменные, описанные вне процедуры и функции,  называ-
ются глобальными переменными и располагаются в сегменте дан-
ных. Переменные, описанные в самой  процедуре  или  функции,
называются локальными переменными и располагаются в сегменте
стека.

                       Сегмент данных

     Максимальный размер сегмента данных равен  65520  байт.
При компоновке программы (что автоматически осуществляется в
конце компиляции программы) глобальные переменные всех моду-
лей, используемых программой, а также собственные глобальные
переменные программы, размещаются в сегменте данных.
     Если для глобальных переменных  требуется  более  65520
байт, то следует распределить большие структуры в виде дина-
мических переменных. Дальнейшее  описание  этой  темы  можно
найти в разделе "Указатели и динамические переменные" насто-
ящей главы.

                       Сегмент стека

     Размер сегмента стека устанавливается с помощью  дирек-
тивы  компилятора  $M  и  лежит  в пределах от 1024 до 65520
байт. По умолчанию размер стека равен 16384 байт.
     При каждой активизации (вызове) процедуры или функции в
стек помещается множество локальных переменных. При заверше-
нии работы память, занимаемая локальными переменными,  осво-
бождается.  В любой момент выполнения программы общий размер
локальных переменных в активных  процедурах  и  функциях  не
должен превышать размера сегмента стека.

                                - 3 -


     Директива компилятора $S  используется  для  проведения
проверок  переполнения стека в программе. В состоянии {$S+},
принятом по умолчанию, генерируется код, осуществляющий про-
верку переполнения стека в начале каждой процедуры или функ-
ции. В состоянии {$S-} такие проверки не  проводятся.  Пере-
полнение  стека  может  вызвать  аварийное завершение работы
системы, поэтому не следует отменять  проверки  стека,  если
нет  абсолютной уверенности в том, что переполнения не прои-
зойдет.

                   Абсолютные переменные

     Переменные можно описать так, что  они  будут  распола-
гаться по определенному адресу в памяти, и в этом случае они
называются абсолютными переменными. Описание таких  перемен-
ных должно содержать после типа абсолютное предложение:

              --------    -----------    -   -----------
абсолютное-->(absolute)-->!целое без!-->(:)--!целое без!---->
предложение   -------- !  !знака    !    -   !знака    ! ^
                       !  -----------        ----------- !
                       !    --------------------------   !
                       ---->!идентификатор переменной!----
                            --------------------------

     Отметим, что список идентификаторов в описании перемен-
ной при указании предложения absolute может содержать только
один идентификатор.
     Первая часть предложения absolute  содержит  сегмент  и
смещение,  то есть адрес, по которому переменная должна быть
размещена.

CrtMode   : byte absolute $0040:$0049;
monochrome Buffer : array[1..25,1..80] of
record
  character,
  attribute : char
end
absolute  $B000:$0000;

                                - 4 -


     Первая константа обозначает базу сегмента, а вторая оп-
ределяет  смещение  внутри  этого сегмента. Обе константы не
должны выходить за пределы диапазона от $0000 до $FFFF (от 0
до 65535).
     Вторая часть предложения absolute используется для опи-
сания  переменной,  которая помещается "поверх" другой пере-
менной, то есть по тому же самому адресу, что и другая пере-
менная.

var
  Str: string[32];
  StrLen: byte absolute Str;

     Это описание указывает, что  переменная  StrLen  должна
размещаться  с  того же адреса, что и переменная Str, а пос-
кольку первый байт строковой переменной содержит  динамичес-
кую длину строки, то StrLen будет содержать длину Str.

                    Ссылки на переменные

     Ссылка на переменную может обозначать следующее:
     - переменную;
     - компонент в переменной  структурного  или  строкового
типа;
     - динамическую переменную, на которую  указывает  пере-
менная типa указатель.
     Синтаксис ссылки на переменную имеет вид:

                 ---------------
ссылка на------->!идентификатор!----------------------------->
переменную   !   !переменной   !       ^ ^                 !
             !   ---------------       ! ! --------------  !
             !   -----------------     ! --!квалификатор!<--
             !-->!приведенный тип!-----!   --------------
             !   !переменной     !     !
             !   -----------------     !
             !   ---------------    -  !
             --->!вызов функции!-->(^)--
                 ---------------    -

                                - 5 -



     Отметим, что синтаксис ссылки на  переменную  допускает
использовать вызов функции в качестве указателя-функции. По-
лученный в результате  указатель  затем  разыменовывается  с
тем, чтобы обозначать динамическую переменную.

                       Квалификаторы

     Обращение к функции  представляет  собой  идентификатор
переменной  с несколькими квалификаторами или без них, кото-
рые изменяют значение обращения к функции.

                  --------
квалификатор----->!индекс!--------------------->
                ! --------              ^
                !   -----------------   !
                !-->!десигнатор поля!---!
                !   -----------------   !
                !            -          !
                ----------->(^)----------
                             -

     Идентификатор массива без квалификатора является  ссыл-
кой на весь массив, например:

     Results

     Идентификатор массива с указанным  индексом  обозначает
конкретный  элемент массива, в данном случае структурную пе-
ременную:

     Results[Current+1]

     В случае, если элементом является запись,  за  индексом
можно  указать обозначение поля. В этом случае ссылка на пе-
ременную означает конкретное поле конкретного элемента  мас-
сива:
            Results[Current+1].data


                                - 6 -



     Обозначение поля в указателе-поле может  сопровождаться
символом  указателя (^) с тем, чтобы указать  различие между
указателем-полем и динамической переменной,  на  которую  он
указывает.

 Results[Current+1].data^

     Если переменная, на которую указывается, является  мас-
сивом, то можно добавить индексы для обозначения компонентов
этого массива.

 Results[Current+1].data^[J]

                 Массивы, строки и индексы

     Конкретный элемент массива обозначается с помощью ссыл-
ки на переменную массива, за которой указывается индекс, оп-
ределяющий данный элемент.
     Конкретный символ в строковой переменной обозначается с
помощью  ссылки на строковую переменную, за которой указыва-
ется индекс, определяющий позицию символа.

           -       -----------         -
индекс--->([)----->!выражение!------->(])---->
           -    ^  -----------   !     -
                !      -         !
                ------(,)<--------
                       -

     Индексные выражения обозначают компоненты в  соответст-
вующей размерности массива. Число выражений не должно превы-
шать числа индексных типов в описании массива.  Более  того,
тип  каждого выражения должен быть совместимым по присваива-
нию с соответствующим индексным типом.
     В случае многомерного массива одинаково можно использо-

                                - 7 -


вать  несколько  индексов или несколько выражений в индексе.
Например:

     Matrix[I][J]

тождественно

     Matrix[I,J]

     Строковую переменную можно проиндексировать  с  помощью
одиночного  индексного  выражения,  значение которого должно
быть в диапазоне 0...n, где n - указанный в описании  размер
строки. Это дает доступ к каждому символу в строковом значе-
нии, если значение символа имеет тип char.
     Первый символ строковой переменной (индекс 0)  содержит
динамическую  длину  строки;  то есть Length(S) тождественно
Ord(S[0]). Если атрибуту длины  присваивается  значение,  то
компилятор  не  проверяет,  является  ли это значение меньше
описанного размера строки. Вы можете указать индекс строки и
вне ее текущей динамической длины. В этом случае считываемые
символы будут случайными, а присваивания вне  текущей  длины
не повлияют на действительное значение строковой переменной.

                 Записи и десигнаторы полей

     Конкретное поле переменной-записи  обозначается  с  по-
мощью ссылки на переменную-запись, после которой указывается
обозначение поля, специфицирующее это поле.

                       -     --------------------
десигнаторы полей---->(.)--->!идентификатор поля!----->
                       -     --------------------

     Приведем несколько примеров десигнаторов полей:

Today.year Results[1].count Result[1].when.month

     В операторе, входящем в оператор with, обозначению поля

                                - 8 -


не  должна  предшествовать  ссылка на переменную, содержащую
запись.

       Переменные-указатели и динамические переменные

     Значением переменной-указателя  является  или  nil  (то
есть  пустое  значение),  или адрес значения, указывающий на
динамическую переменную.
     Ссылка на динамическую переменную, на которую указывает
переменная-указатель,  записывается в виде переменной-указа-
теля, после которой ставится символ указателя (^).
     Динамические переменные и значения их указателей созда-
ются  с помощью стандартных процедур New и GetMem. Вы можете
использовать операцию @ и стандартную функцию Ptr для созда-
ния  значений  указателя, которые рассматриваются как указа-
тели динамических переменных.
     Значение nil не указывает ни на какую  переменную.  Ре-
зультат  будет  неопределенным, если вы попытаетесь получить
доступ к динамической переменной при неопределенном значении
указателя или указателе, равном nil.
     Приведем несколько примеров ссылок (указателей) на  ди-
намические переменные:

P1 P1.sibling Results[1].data

                Приведение типов переменных

     Ссылка на переменную одного типа может быть  преобразо-
вана  в ссылку на переменную другого типа с помощью приведе-
ния типов переменных.

                  ---------------    -    ------------    -
приведение типа-->!идентификатор!-->(()-->!ссылка на !-->())-->
переменной        !типа         !    -    !переменную!    -
                  ---------------         ------------

     Когда приведение типов применяется к ссылке на перемен-
ную,  ссылка на переменную рассматривается как экземпляр ти-

                                - 9 -


па, представленного идентификатором типа. Размер  переменной
(число байтов, занимаемых переменной) должен быть равен раз-
меру типа, представленного идентификатором типа. После  при-
ведения  типа  переменной  можно  указать один или несколько
квалификаторов, если это допускается указанным типом.
     Приведем несколько примеров приведения  типов  перемен-
ных:

type
  ByteRec = record
             lo, hi: byte;
            end;
  WordRec = record
             low, high: word;
            end;
  PtrRec = record
            ofs, seg: word;
           end;
  BytePtr = ^Byte;
var
  B: byte;
  W: word;
  L: longint;
  P: pointer;
begin
  W := $1234;
  B := ByteRec(W).lo;
  ByteRec(W).hi := 0;
  L := $1234567;
  W := WordRec(L).lo;
  B := BytePtr(L)^;
  P := Ptr($40,$49);
  W := PtrRec(P).seg;
  Inc(PtrRec(P).seg;
end.

     Обратите внимание на использование для доступа к  млад-
шим  и  старшим байтам слова типа ByteRec: это соответствует

                                - 10 -


встроенным функциям Lo и Hi, только над левой частью в  опе-
рации  присваивание может выполняться приведение типа. Отме-
тим также, что для доступа к младшим и старшим словам  длин-
ного  целого, а также к смещению и адресу сегмента указателя
используются типы WordRec и PtrRec.


