ЭЛЕКТРОННАЯ БИБЛИОТЕКА КОАПП |
Сборники Художественной, Технической, Справочной, Английской, Нормативной, Исторической, и др. литературы. |
Часть 6 Глава 4. Переменные Описания переменных Описание переменной представляет собой список идентификаторов, которые обозначают новые переменные и их типы. ЪДДДДДДДДДї ХНё ЪДДДї ХНё описаниеДДДісписок ГДДі:іДДітипГДВДДДДДДДДДДДДДДДДДДі;іДДД переменной іидентифи-і ФНѕ АДДДЩ і ФНѕ ікаторов і і ЪДДДДДДДДДДДї і АДДДДДДДДДЩ АДі оператор ГДЩ і absolute і АДДДДДДДДДДДЩ Тип, задаваемый для переменных, может быть идентификатором типа, который был ранее описан в разделе описания типов того же самого блока, или блока, в который входит данный блок, или модуля, или же этот тип может быть новым определением типа. При указании идентификатора в списке идентификаторов описания переменной этот идентификатор имеет силу идентификатора переменной в том блоке, где это описание было указано. К этой переменной можно обращаться из любого места этого блока, если ее иден тификатор не переопределен в блоке, входящем в первый. Переопределение означает, что для новой переменной используется тот же самый идентификатор, но это использование не оказывает влияния на значение первоначальной переменной. Приведем пример раздела описания переменной: var X,Y,Z: real; I,J,K: integer; Digit: 0..9; C: Color; Done,Error: boolean; Operator: (plus, minus, times); Hue1,Hue2: set of Color; Today: Date; Results: MeasureList; P1,P2: Person; Matrix: array[1..10,1..10] of real; Переменные, описанные вне процедуры и функции, называются глобальными переменными и располагаются в сегменте данных. Переменные, описанные в самой процедуре или функции, называются локальными переменными и располагаются в сегменте стека. Сегмент данных Максимальный размер сегмента данных равен 65520 байт. При компоновке программы (что автоматически осуществляется в конце компиляции программы) глобальные переменные всех модулей, используемых программой, а также собственные глобальные переменные про граммы размещаются в сегменте данных. Если для глобальных переменных требуется более 65520 байт, то следует распределить большие структуры в виде динамических переменных. Примечание: Дальнейшее описание этой темы можно найти в разделе "Указатели и динамические переменные" настоящей главы. Сегмент стека Размер сегмента стека устанавливается с помощью директивы компилятора $M и лежит в пределах от 1024 до 65520 байт. По умолчанию размер стека равен 8192 байтам. При каждой активизации (вызове) процедуры или функции в стек помещается множество локальных переменных. При завершении работы память, занимаемая локальными переменными, освобождается. В любой момент выполнения программы общий размер локальных переме нных в активных процедурах и функциях не должен превышать размера сегмента стека. Директива компилятора $S используется для проведения проверок переполнения стека в программе. В состоянии {$S+}, принятом по умолчанию, генерируется код, осуществляющий проверку переполнения стека в начале каждой процедуры или функции. В состоянии { $S-} такие проверки не проводятся. Переполнение стека может вызвать аварийное завершение работы системы, поэтому не следует отменять проверки стека, если нет абсолютной уверенности в том, что переполнения не произойдет. Абсолютные переменные Переменные можно описать так, что они будут располагаться по определенному адресу в памяти, и в этом случае они называются абсолютными переменными. Описание таких переменных должно содержать после типа оператор absolute: ХННННННННё ЪДДДДДДДДДї ХНё ЪДДДДДДДДДї оператор ДДДіabsoluteГВДіцелое безіДДі:ГДДґцелое безГДДДДДДДД absolute ФННННННННѕі ізнака і ФНѕ ізнака і і АДДДДДДДДДЩ АДДДДДДДДДЩ і і ЪДДДДДДДДДДДДДДДДДДДДДДДДї і АДДДіидентификатор переменнойіДДДЩ АДДДДДДДДДДДДДДДДДДДДДДДДЩ Отметим, что список идентификаторов в описании переменной при указании оператора absolute может содержать только один идентификатор. Первая часть оператора absolute содержит сегмент и смещение, то есть адрес, по которому переменная должна быть размещена. CrtMode : byte absolute $0040:$0049; Первая константа обозначает базу сегмента, а вторая определяет смещение внутри этого сегмента. Обе константы не должны выходить за пределы диапазона от $0000 до $FFFF (от 0 до 65535). Вторая часть оператора absolute используется для описания переменной, которая помещается "поверх" другой переменной, то есть по тому же самому адресу, что и другая переменная. var Str: string[32]; StrLen: byte absolute Str; Это описание указывает, что переменная StrLen должна размещаться с того же адреса, что и переменная Str, а поскольку первый байт строковой переменной содержит динамическую длину строки, то StrLen будет содержать длину Str. Ссылки на переменные Ссылка на переменную может обозначать следующее: - переменную; - компонент в переменной структурного или строкового типа; - динамическую переменную, на которую указывает переменная типa указатель. Синтаксис ссылки на переменную имеет вид: ЪДДДДДДДДДДДДДї ссылка наДДДДВДДіидентификаторГДДДДДДДДДДДДДДДДДДДДДДДДДДДВДДДДД переменную і іпеременной і і і АДДДДДДДДДДДДДЩ і і ЪДДДДДДДДДДДДї і і ЪДДДДДДДДДДДДДДДї і АДіквалификаторіДЩ ГДДіприведенный типГДДДДДґ АДДДДДДДДДДДДЩ і іпеременной і і і АДДДДДДДДДДДДДДДЩ і і ЪДДДДДДДДДДДДДї ХНё і АДДівызов функцииГДДі^ГДЩ АДДДДДДДДДДДДДЩ ФНѕ Отметим, что синтаксис ссылки на переменную допускает использовние вызова функции в качестве указателя-функции. Полученный в результате указатель затем разыменовывается с тем, чтобы обозначать динамическую переменную. Квалификаторы Обращение к функции представляет собой идентификатор переменной с несколькими квалификаторами или без них, которые изменяют значение обращения к функции. ЪДДДДДДї квалификаторДДДДВіиндексіДДДДДДДДДДДДДДДДДДДДД і АДДДДДДЩ і ЪДДДДДДДДДДДДДДДї і ГДДідесигнатор поляГДДДґ і АДДДДДДДДДДДДДДДЩ і і ХНё і АДДДДДДДДДДі^ГДДДДДДДДДЩ ФНѕ Идентификатор массива без квалификатора является ссылкой на весь массив, например: Results Идентификатор массива с указанным индексом обозначает конкретный элемент массива, в данном случае структурную переменную: Results[Current+1] В случае, если элементом является запись, за индексом можно указать обозначение поля. В этом случае ссылка на переменную означает конкретное поле конкретного элемента массива: Results[Current+1].data Чтобы указать различие между указателем-полем и динамической переменной, на которую он указывает, за десигнатором поля в указателе-поле может следовать символ указателя (^). Results[Current+1].data^ Если переменная, на которую имеется ссылка, является массивом, то можно добавить индексы для обозначения компонентов этого массива. Results[Current+1].data^[J] Массивы, строки и индексы Конкретный элемент массива обозначается с помощью ссылки на переменную массива, за которой указывается индекс, определяющий данный элемент. Конкретный символ в строковой переменной обозначается с помощью ссылки на строковую переменную, за которой указывается индекс, определяющий позицию символа. ХНё ЪДДДДДДДДДї ХНё индексДДДі[ГДДДДДівыражениеГДДДВДДДі]ГДДДДДДДДДДДДДДД ФНѕ АДДДДДДДДДЩ і ФНѕ і ХНё і АДДДДДґ,іДДДДДДДЩ ФНѕ Индексные выражения обозначают компоненты в соответствующей размерности массива. Число выражений не должно превышать числа индексных типов в описании массива. Более того, тип каждого выражения должен быть совместимым по присваиванию с соответствующи м индексным типом. В случае многомерного массива можно использовать несколько индексов или несколько выражений в индексе. Например: Matrix[I][J] что тождественно записи: Matrix[I,J] Строковую переменную можно проиндексировать с помощью одиночного индексного выражения, значение которого должно быть в диапазоне 0...n, где n - указанный в описании размер строки. Это дает доступ к каждому символу в строковом значении, если значение символа имеет тип char. Первый символ строковой переменной (индекс 0) содержит динамическую длину строки, то есть Length(S) тождественно Ord(S[0]). Если атрибуту длины присваивается значение, то компилятор не проверяет, меньше ли это значение описанного размера строки. Вы можете указать индекс строки и вне ее текущей динамической длины. В этом случае считываемые символы будут случайными, а присваивания вне текущей длины не повлияют на действительное значение строковой переменной. При разрешении с помощью директивы компилятора {$X+} расширенного синтаксиса значение типа PChar может индексироваться c помощью одиночного индексного выражения типа Word. Индексное выражение задает добавляемое к указателю символа перед его разымено ванием для получения ссылки на переменную типа Char смещение. Примечание: Более подробно о типе PChar рассказывается в Главе 13 "Модуль Strings". Записи и десигнаторы полей Конкретное поле переменной-записи обозначается с помощью ссылки на переменную-запись, после которой указывается обозначение поля, специфицирующее это поле. ХНё ЪДДДДДДДДДДДДДДДДДДї десигнаторы полейДДДДі.ГДДДіидентификатор поляГДДДДДДДДДД ФНѕ АДДДДДДДДДДДДДДДДДДЩ Приведем несколько примеров десигнаторов полей: Today.year Results[1].count Result[1].when.month В операторе, входящем в оператор with, обозначению поля не должна предшествовать ссылка на переменную, содержащую запись. Десигнаторы компонентов объекта Формат десигнатора компонента объекта совпадает с форматом десигнатора поля записи. То есть, он состоит из экземпляра (ссылки на переменную), за которым следует точка и идентификатор компонента. Десигнатор компонента, который обозначает метод, назыв ается десигнатором метода. К экземпляру объектного типа можно применить оператор with. В этом случае при ссылке на компоненты объектного типа экземпляр и точку можно опустить. Экземпляр и точку можно опустить также в любом блоке метода. При этом эффект будет тот же, что и при записи перед ссылкой на компонент Self и точки. Переменные-указатели и динамические переменные Значением переменной-указателя является или nil (то есть пустое значение), или адрес значения, указывающий на динамическую переменную. Ссылка на динамическую переменную, на которую указывает переменная-указатель, записывается в виде переменной-указателя, после которой ставится символ указателя (^). Динамические переменные и значения их указателей создаются с помощью стандартных процедур New и GetMem. Для создания значений указателя, которые рассматриваются как указатели динамических переменных, вы можете использовать операцию @ и стандартную ф ункцию Ptr. Значение nil не указывает ни на какую переменную. Если вы попытаетесь получить доступ к динамической переменной при неопределенном значении указателя или указателе, равном nil, результат будет неопределенным. Приведем несколько примеров ссылок на динамические переменные: P1^ P1.sibling^ Results[1].data^ Приведение типов переменных Ссылка на переменную одного типа может быть преобразована в ссылку на переменную другого типа с помощью приведения типов переменных. ЪДДДДДДДДДДДДДї ХНё ЪДДДДДДДДДДї ХНё приведение типаДДіидентификаторіДДі(ГДДіссылка на іДДі)ГДДДД переменной ітипа і ФНѕ іпеременнуюі ФНѕ АДДДДДДДДДДДДДЩ АДДДДДДДДДДЩ Когда приведение типов применяется к ссылке на переменную, ссылка на переменную рассматривается как экземпляр типа, представленного идентификатором типа. Размер переменной (число байт, занимаемых переменной) должен быть равен размеру типа, представл енного идентификатором типа. После приведения типа переменной можно указать один или несколько квалификаторов типа (если это допускается указанным типом). Приведем несколько примеров приведения типов переменных: 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: это соответствует встроенным функциям Lo и Hi, только над левой частью в операции присваивание может выполняться приведение типа. Отметим также, что для до ступа к младшим и старшим словам длинного целого типа (LongInt), а также к смещению и адресу сегмента указателя используются типы WordRec и PtrRec. Турбо Паскаль также полностью поддерживает приведение типов для процедурных типов. Например, имея такие описания: type Func = function(X: Integer): Integer; var F: Func; P: Pointer; N: Integer; вы можете построить следующие присваивания: F := Func(P); { присвоить F значение процедурного типа в P } Func(P) := F; { присвоить P значение процедурного типа в F } @F := P; { присвоить F значение-указатель в P } P := @F; { присвоить P значение-указатель в F } N := F(N); { вызвать функцию через F } N := Func(P)(N); { вызвать функцию через P } Обратите в частности внимание на операцию получения адреса @, которая применяется к переменной процедурного типа. Ее можно использовать в левой части присваивания. Кроме того, отметьте приведение типа на последней строке при вызове функции через пер еменную-указатель. |