- •Часть I. Язык Borland Pascal...................................12
- •Глава 1. Что такое программа Borland Pascal?...................12
- •Глава 2. Лексемы...............................................22
- •Глава 3. Константы.............................................32
- •Глава 4. Типы..................................................34
- •Глава 5. Переменные и типизированные константы.................72
- •Глава 6. Выражения.............................................93
- •Глава 7. Операторы............................................117
- •Глава 8. Блоки, локальность и область действия................133
- •Глава 9. Процедуры и функции..................................139
- •Глава 10. Программы и модули..................................170
- •Глава 11. Динамически компонуемые библиотеки..................180
- •Глава 12. Библиотеки исполняющей системы......................194
- •Глава 13. Стандартные процедуры и функции.....................199
- •Глава 14. Ввод и вывод........................................215
- •Глава 15. Использование сопроцессора 80x87....................248
- •Глава 16. Модуль Dоs..........................................259
- •Глава 17. Программирование в защищенном режиме dos............270
- •Глава 18. Строки с завершающим нулем..........................297
- •Глава 19. Использование графического интерфейса Borland.......308
- •Глава 20. Использование оверлеев..............................329
- •Часть III. В среде Borland Pascal.............................348
- •Глава 21. Использование памяти................................348
- •Глава 22. Вопросы управления..................................388
- •Глава 23. Автоматическая оптимизация..........................405
- •Часть IV. Использование Borland Pascal с языком ассемблера....411
- •Глава 24. Встроенный ассемблер................................411
- •Глава 25. Компоновка с программами на языке ассемблера........437
- •Часть II "Библиотеки исполняющей системы" содержит информа-
- •Часть I. Язык Borland Pascal
- •Глава 1. Что такое программа Borland Pascal?
- •Глава 2. Лексемы
- •Глава 3. Константы
- •Глава 4. Типы
- •Глава 5. Переменные и типизированные константы
- •Глава 6. Выражения
- •Глава 7. Операторы
- •Глава 8. Блоки, локальность и область действия
- •Глава 9. Процедуры и функции
- •Глава 10. Программы и модули
- •Глава 11. Динамически компонуемые библиотеки
- •Часть II. Глава 12. Библиотеки исполняющей системы
- •Глава 13. Стандартные процедуры и функции
- •Глава 14. Ввод и вывод
- •Глава 15. Использование сопроцессора 80x87
- •Глава 16. Модуль Dоs
- •Глава 17. Программирование в защищенном режиме dos
- •Глава 18. Строки с завершающим нулем
- •Глава 19. Использование графического интерфейса Borland
- •Глава 20. Использование оверлеев
- •Часть III. В среде Borland Pascal
- •Глава 21. Использование памяти
- •Глава 22. Вопросы управления
- •Глава 23. Автоматическая оптимизация
- •Часть IV. Использование Borland Pascal с языком ассемблера
- •Глава 24. Встроенный ассемблер
- •Глава 25. Компоновка с программами на языке ассемблера
Глава 18. Строки с завершающим нулем
─────────────────────────────────────────────────────────────────
В Borland Pascal поддерживается класс символьных строк, ко-
торые называются строками, завершающимися нулем. Благодаря расши-
ренному синтаксису Borland Pascal и модулю Strings ваши программы
(как для DOS, так и для Windows) могут использовать строки с за-
вершающим нулем путем задания в операторе uses модуля Strings.
Что такое строка с завершающим нулем?
─────────────────────────────────────────────────────────────────
В Borland Pascal строки обычного типа (String) хранятся как
байт длины, за которым следует последовательность символов. Мак-
симальная длина строки в Паскале равна 255 символам. Таким обра-
зом, строка Паскаля занимает от 1 до 256 байт памяти.
Строки с завершающим нулем не содержат байта длины. Вместо
этого они состоят из последовательности ненулевых символов, за
которыми следует символ NULL (#0). Никаких ограничений на длину
строк с завершающим нулем не накладывается, но 16-разрядная архи-
тектура DOS и Windows ограничивает их размер 65535 символами.
Функции модуля Strings
─────────────────────────────────────────────────────────────────
Borland Pascal не имеет встроенных подпрограмм, предназна-
ченных специально для работы со строками с завершающим нулем. Эти
функции вы можете найти в модуле Strings. Среди них вы найдете
функцию StrPCopy, которую можно использовать для копирования
строки Паскаля в строку с завершающим нулем, и StrPos, используе-
мую для преобразования строки с завершающим нулем в строку Паска-
ля. Приведем краткое описание каждой функции:
B.Pascal 7 & Objects/LR - 298 -
Функции модуля Strings
┌──────────────┬────────────────────────────────────────────────┐
│ Функция │ Описание │
├──────────────┼────────────────────────────────────────────────┤
│ StrCat │ Добавляет исходную строку к концу целевой стро-│
│ │ ки и возвращает указатель на целевую строку. │
├──────────────┼────────────────────────────────────────────────┤
│ StrComp │ Сравнивает две строки S1 и S2. Возвращает│
│ │ значение < 0, если S1 < S2, равное 0, если S1 =│
│ │ S2 и > 0, если S1 > S2. │
├──────────────┼────────────────────────────────────────────────┤
│ StrCopy │ Копирует исходную строку в целевую строку и│
│ │ возвращает указатель на целевую строку. │
├──────────────┼────────────────────────────────────────────────┤
│ StrECopy │ Копирует исходную строку в целевую строку и│
│ │ возвращает указатель на конец целевой строки. │
├──────────────┼────────────────────────────────────────────────┤
│ StrIComp │ Сравнивает две строки без различия регистра│
│ │ символов. │
├──────────────┼────────────────────────────────────────────────┤
│ StrLCat │ Присоединяет исходную строку к концу целевой│
│ │ строки. При этом обеспечивается, что длина ре-│
│ │ зультирующей строки не превышает заданного мак-│
│ │ симума. Возвращается указатель на строку-ре-│
│ │ зультат. │
├──────────────┼────────────────────────────────────────────────┤
│ StrLComp │ Сравнивает две строки с заданной максимальной│
│ │ длиной. │
├──────────────┼────────────────────────────────────────────────┤
│ StrLCopy │ Копирует заданное число символов из исходной│
│ │ строки в целевую строку и возвращает указатель│
│ │ на целевую строку. │
├──────────────┼────────────────────────────────────────────────┤
│ StrEnd │ Возвращает указатель на конец строки, то есть│
│ │ указатель на завершающий строку нулевой символ.│
├──────────────┼────────────────────────────────────────────────┤
│ StrDispose │ Уничтожает ранее выделенную строку. │
├──────────────┼────────────────────────────────────────────────┤
│ StrLen │ Возвращает длину строки. │
├──────────────┼────────────────────────────────────────────────┤
│ StrLIComp │ Сравнивает две строки с заданной максимальной│
│ │ длиной без различия регистра символов. │
├──────────────┼────────────────────────────────────────────────┤
│ StrLower │ Преобразует строку в нижний регистр и возвраща-│
│ │ ет указатель на нее. │
├──────────────┼────────────────────────────────────────────────┤
│ StrMove │ Перемещает блок символов из исходной строки в│
│ │ целевую строку и возвращает указатель на целе-│
│ │ вую строку. Два блока могут перекрываться. │
├──────────────┼────────────────────────────────────────────────┤
│ StrNew │ Выделяет для строки память в динамически рас-│
│ │ пределяемой области. │
├──────────────┼────────────────────────────────────────────────┤
B.Pascal 7 & Objects/LR - 299 -
│ StrPas │ Преобразует строку с завершающим нулем в строку│
│ │ Паскаля. │
├──────────────┼────────────────────────────────────────────────┤
│ StrPCopy │ Копирует строку Паскаля в строку с завершающим│
│ │ нулем и возвращает указатель на строку с завер-│
│ │ шающим нулем. │
├──────────────┼────────────────────────────────────────────────┤
│ StrPos │ Возвращает указатель на первое вхождение задан-│
│ │ ной подстроки в строке, или nil, если подстрока│
│ │ в строке не содержится. │
├──────────────┼────────────────────────────────────────────────┤
│ StrRScan │ Возвращает указатель на последнее вхождение│
│ │ указанного символа в строку, или nil, если сим-│
│ │ вол в строке отсутствует. │
├──────────────┼────────────────────────────────────────────────┤
│ StrScan │ Возвращает указатель на первое вхождение ука-│
│ │ занного символа в строку, или nil, если символ│
│ │ в строке отсутствует. │
├──────────────┼────────────────────────────────────────────────┤
│ StrUpper │ Преобразует строку в верхний регистр и возвра-│
│ │ щает указатель на нее. │
└──────────────┴────────────────────────────────────────────────┘
Использование строк с завершающим нулем
─────────────────────────────────────────────────────────────────
Строки с завершающим нулем хранятся в виде символьных масси-
вов с нулевой базой (начинающихся с 0) с индексом целого типа, то
есть в виде массива:
array[0..X] of Char;
где X - положительное ненулевое целое число. Такие массивы назы-
ваются символьными массивами с нулевой базой. Приведем некоторые
примеры описаний символьных массивов с нулевой базой, которые мо-
гут использоваться для хранения завершающихся нулем строк.
type
TIdentifier = array[0..15] of Char;
TFileName = array[0..79] of Char;
TMemoText = array[0..1023] of Char;
B.Pascal 7 & Objects/LR - 300 -
Более всего строки Паскаля и строки с завершающим нулем от-
личаются интенсивностью использования указателей. Borland Pascal
выполняет операции с этими указателями, используя набор правил
расширенного синтаксиса. Кроме того, в Borland Pascal имеется
встроенный тип PChar, который представляет собой указатель на
строку с завершающим нулем. В модуле System тип PChar определяет-
ся следующим образом:
type PChar = ^Char;
Правилами расширенного синтаксиса управляет директива компи-
лятора $X. В состоянии {$X+} (по умолчанию) расширенный синтаксис
разрешен. Правила расширенного синтаксиса описываются в следующих
разделах.
B.Pascal 7 & Objects/LR - 301 -
Символьные указатели и строковые литералы
─────────────────────────────────────────────────────────────────
При разрешении расширенного синтаксиса строковый литерал
совместим по присваиванию с типом PChar. Это означает, что пере-
менной типа PChar можно присвоить строковый литерал. Например:
var
P: PChar;
.
.
begin
P := 'Привет...';
end;
В результате такого присваивания указатель указывает на об-
ласть памяти, содержащую строку с завершающим нулем, являющуюся
копией строкового литерала. Компилятор записывает строковые лите-
ралы в сегмент данных, аналогично описанию "скрытых" типизирован-
ных констант:
const
TempString: array[0..14] of Char = 'Привет...'#0;
var
P: PChar;
.
.
begin
P := @TempString;
end;
Когда соответствующие формальные параметры имеют тип Char,
строковые литералы вы можете использовать как фактические пара-
метры при вызовах процедур и функций. Например, если имеется про-
цедура с описанием:
procedure PrintStr(Str: PChar);
то допустимы следующие вызовы процедуры:
procedure PrintStr('Строка для проверки');
PrintStr(#10#13);
Аналогично тому, как это происходит при присваивании, компи-
лятор генерирует строку с завершающим нулем, представляющую собой
копию литеральной строки в сегменте данных, и передает указатель
на эту область памяти в параметре Str процедуры PrintStr.
Наконец, типизированная константа типа PChar может инициали-
зироваться строковой константой. Это справедливо также для струк-
турных типов, таких как массивы PChar и записи, а также объекты
PChar.
B.Pascal 7 & Objects/LR - 302 -
const
Message: PChar = 'Program terminated';
Prompt: PChar = 'Enter values: ';
Digits; array [0..9] of PChar = {
'Zero', 'One', 'Two', 'Three', 'Four', 'Five',
'Six', 'Seven', Eight', 'Nine'};
Строковая выражение-константа всегда вычисляется как строка
Паскаля, даже если она инициализируется как типизированная конс-
танта типа PChar. Таким образом, строковое выражение-константа
всегда ограничено длиной в 255 символов.
Символьные указатели и символьные массивы
─────────────────────────────────────────────────────────────────
Если вы с помощью директивы $X разрешаете расширенный син-
таксис, то символьный массив с нулевой базой совместим с типом
PChar. Это означает, что там, где предполагается использование
типа PChar, может использоваться символьный массив с нулевой ба-
зой. Когда символьный массив используется вместо значения PChar,
компилятор преобразует символьный массив в указатель-константу,
значение которой соответствует адресу первого элемента массива.
Например:
var
A: array[0..63] of Char;
P: PChar;
.
.
.
begin
P := A;
PrintStr(A);
PrintStr(P);
end;
Благодаря оператору присваивания P теперь указывает на пер-
вый элемент массива A, поэтому PrintStr вызывается дважды с одним
и тем же значением.
Вы можете инициализировать типизованную константу, имеющую
тип символьного массива с нулевой базой, с помощью строкового ли-
терала, имеющего меньшую длину, чем размер массива. Оставшиеся
символы устанавливаются в значение NULL (#0), и массив будет со-
держать строку с завершающим нулем.
type
TFileName = array[0..79] of Char;
const
FileNameBuf: TfileName = 'TEST.PAS';
FileNamePtr: PCahr = FileNameBuf;
B.Pascal 7 & Objects/LR - 303 -
Индексирование символьного указателя
─────────────────────────────────────────────────────────────────
Так как символьный массив с нулевой базой совместим с сим-
вольным указателем, символьный указатель можно индексировать ана-
логично символьному массиву с нулевой базой.
var
A: array[0..63] of Char;
P: PChar;
Ch: Char;
.
.
.
begin
P := A;
Ch := A[5];
Ch := P[5];
end;
Оба последних присваивания присваивают Ch значение, содержа-
щееся в шестом символе-элементе A.
При индексировании символьного указателя индекс задает безз-
наковое смещение, которое добавляется к указателю перед его разы-
менованием. Таким образом, P[0] эквивалентно P^ и задает символ,
на который указывает P. P[1] задает символ справа от того, на ко-
торый указывает P, P[2] задает следующий символ и т.д. Для целей
индексирования PChar ведет себя таким образом, как если бы он
описывался:
type
TCharArray = array[0..65535] of Char;
Pchar = ^TCharArray;
Компилятор при индексировании символьного указателя не вы-
полняет проверку диапазона, так как у него нет информации о типе,
по которой можно определить максимальную длину строки с завершаю-
щим нулем, на которую указывает символьный указатель.
Показанная ниже функция StrUpper иллюстрирует использование
символьного указателя для преобразования строки с завершающим ну-
лем в верхний регистр.
function StrUpper(Srt: Pchar): Pchar;
var
I: Word;
begin
I := 0;
while Str[I] <> #0 do
begin
Str[I] := UpCase(Str[I]);
Inc(I);
B.Pascal 7 & Objects/LR - 304 -
end;
StrUpper := Str;
end;
Обратите внимание, что StrUppper - это функция, а не проце-
дура, и что она всегда возвращает значение, которое передавалось
ей в качестве параметра. Так как расширенный синтаксис допускает
игнорирование результата функции, StrUpper может интерпретиро-
ваться, как процедура:
StrUpper(A);
PrintStr(A);
Однако, StrUpper всегда возвращает передаваемое ей значение,
приведенные выше операторы можно скомбинировать в один:
PrintStr(StrUpper(A));
Вложенные вызовы функций работы со строками с завершающим
нулем могут оказаться очень удобными, когда вы хотите указать оп-
ределенную взаимосвязь между последовательными операциями со
строками.
Операции с символьными указателями
─────────────────────────────────────────────────────────────────
Расширенный синтаксис Borland Pascal позволяет использовать
для работы с символьными указателями отдельные операции. Для уве-
личения или уменьшения смещения в значении указателя можно ис-
пользовать операции плюс (+) и минус (-). Операцию минус (-) мож-
но использовать для вычисления расстояния (разности смещений)
между двумя символьными указателями. Предположим, что P и Q
представляют собой значения тип PChar, а I - значение типа Word.
Тогда допустимы следующие конструкции:
P + I I прибавляется к смещению P
I + P I прибавляется к смещению P
P - I I вычитается из смещения P
P - Q Смещение Q вычитается из смещения P
В операциях P + I и I + P I прибавляется к адресу, задавае-
мому P. При этом получается указатель, который указывает на I
символов после P. В операции P - I I вычитается из адреса, зада-
ваемого P, и получается указатель, указывающий на I символов до
P.
Операция P - Q вычисляет расстояние между Q (младший адрес)
и P (старший адрес). При этом возвращается результат типа Word,
показывающий число символов между Q и P. Эта операция предполага-
ет, что P и Q указывают на один и тот же массив символов. Если
эти два указателя указывают на разные символьные массивы, то ре-
зультат непредсказуем.
B.Pascal 7 & Objects/LR - 305 -
Стандартный синтаксис Borland Pascal позволяет при сравнении
указателей определять только их равенство или неравенство. Расши-
ренный синтаксис (разрешенный по директиве компилятора {$X+})
позволяет применять операции <, >, <= и <= к значениям PChar. За-
метим, однако, что при таких проверках предполагается, что два
сравниваемых указателя указывают на один и тот же массив симво-
лов. По этой причине сравниваются только смещения указателей. Ес-
ли два указателя указывают на различные символьные массивы, то
результат не определен.
var
A, B: array[0..79] of Char;
P, Q: PChar;
begin
P := A; { P указывает на A[0] }
Q := A + 5; { Q указывает на A[5] }
if P < Q then ...; { допустимая проверка,
результат - True }
Q := B; { Q указывает на B[0] }
if P < Q then ...; { результат не определен }
end;
Подробнее об операциях с PChar рассказывается в Главе 6.
Строки с завершающим нулем и стандартные процедуры
─────────────────────────────────────────────────────────────────
Расширенный синтаксис Borland Pascal позволяет применять к
символьным массивам с нулевой базой стандартные процедуры Read,
ReadLn и Val, а к символьным массива с нулевой базой и символьным
указателям - стандартные процедуры Write, WriteLn, Val, Assign и
Rename. Более подробные описания этих процедур можно найти в Гла-
ве 1 ("Справочник по библиотеке") "Справочного руководства прог-
раммиста".
B.Pascal 7 & Objects/LR - 306 -
Пример использования функций с завершающим нулем
─────────────────────────────────────────────────────────────────
Приведем пример исходного кода, показывающий, как можно ис-
пользовать некоторые функции обработки строк. Этот пример исполь-
зован при разработке функции FileSplit в модуле WinDos.
{ максимальные размеры компонентов имени файла }
const
fsPathName = 79; { имя маршрута }
fsDirectory = 67; { имя каталога }
fsFileName = 8; { имя файла }
fsExtension = 4; { расширение имени файла }
{ флаги, возвращаемые FileSplit }
const
fcWildcards = $0008 { трафаретные символы }
fcDirectory = $0004 { имя каталога }
fcFileName = $0002 { имя файла }
fcExtension = $0001 { расширение имени файла }
{ FileSplit разбивает имя файла, заданное маршрутом, на три }
{ компонента. Dir принимает значение диска и каталога с }
{ предшествующей и завершающей обратной косой чертой, Name }
{ принимает значение имени файла, а Ext - расширения с }
{ предшествующей точкой. Если компонент строки-параметра }
{ равен NIL, то соответствующая часть маршрута не }
{ записывается. Если маршрут не содержит данного компонента, }
{ то возвращаемая строка компонента будет пустой. }
{ Максимальные длины строк, возвращаемых в Dir, Name и Ext, }
{ определяются битовыми масками fsDirectory, fsFileName, }
{ fsExtension. Возвращаемое значение представляет собой }
{ комбинацию битовых масок fсDirectory, fсFileName и }
{ fсExtension, показывающую, какие компоненты присутствуют в }
{ маршруте. Если имя и расширение содержат трафаретные }
{ символы (* и ?), то в возвращаемом значении устанавливается }
{ флаг fcWildcards. }
function FileSplit(Path, Dir, Name, Ext: PChar): Word;
var
DirLen, NameLEn, Flags: Word;
NamePtr, ExtPtr: PChar;
begin
NamePtr := StrRScan(Path, '/');
if NamePtr = nil then NamePtr := StrRScan(Path, ':');
if NamePtr = nil then NamePtr := Path else Inc(NamePtr);
ExtPtr := StrScan(NamePtr, '.');
if ExtPtr = nil then ExtPtr := StrEnd(NamePtr);
DirLen := NamePtr - Path;
if DirLen > fsDirectory then DirLen := fsDirectory;
NameLen := ExtPtr - NamePtr;
B.Pascal 7 & Objects/LR - 307 -
if NameLen > fsFilename then NameLen := fsFileName;
Flags := 0;
if (StrScan(NamePtr, '?') <> nil) or
(StrScan(NamePtr, '*') <> nil) then
Falgs := fcWildcards;
if DirLen <> 0 then Flags := Flags or fcDirectory;
if NameLen <> 0 then Flags := Flags or fcFilename;
if ExtPtr[0] <> #0 then Flags := Flags or fcExtension;
if Dir <> nil then StrLCopy(Dir, Path, DirLen);
if Name <> nil then StrLCopy(Name, NamePtr, NameLen);
if Ext <> nil then StrLCopy(Ext, ExtPtr, fsExtension);
FileSplit := Flags:
end;
B.Pascal 7 & Objects/LR - 308 -
───────────────────────────────────────────────────────────────────────