Обучающие курсы:

Обучение профессии "Разработчик C#" + стажировка в Mail.ru
Обучение профессии "Разработчик Python" + трудоустройство
Обучение профессии "Веб-разработчик" + стажировка в Mail.ru


Главная страница
Библиотека (скачать книги)
Скачать софт
Введение в программирование
Стандарты для C++
Уроки по C#
Уроки по Python
HTML
Веб-дизайн
Ассемблер в среде Windows
ActiveX
Javascript
Общее о Линукс
Линукс - подробно
Линукс - новое
Delphi
Паскаль для начинающих
Турбопаскаль
Новости
Партнеры
Наши предложения
Архив новостей





Вторым типом строк, который мы рассмотрим, являются длинные строки, или AnsiString. Выделение памяти под эти строки происходит динамически, а их размер практически неограничен. Длинная строка описывается 32- разрядным указателем (переменной строки). Delphi автоматически выделяет память для такой строки, а также добавляет в конец строки нулевой символ (для совместимости с WIN API). Поскольку переменная длинной строки представляет собой указатель, то несколько переменных могут ссылаться на одно и то же значение без использования дополнительной памяти. Каждая строка AnsiString имеет счетчик ссылок (reference count), в котором содержится количество строковых переменных, ссылающихся на один и тот же адрес. Если переменная типа AnsiString модифицирует строку, то счетчик ссылок декрементируется. Когда счетчик ссылок становится равным нулю, блок памяти, занимаемый строкой, освобождается, а указатель строки принимает нулевое значение. Следующий фрагмент кода иллюстрирует все сказанное выше (листинг 6.31).

Листинг 6.31. Фрагмент кода, демонстрирующий приципы работы с длинными строками

Src, Dst: String; // строки проинициализированы, но память под них // не выделена. Счетчики ссылок для строк равны О
begin
Src
Dst
Dst
'SOURCE STRING';
Src;
Dst + ' + DEST STRING'
// строка размещена в памяти,
// счетчик ссылок равен 1
// строка Dst ссылается на Src,
//счетчик ссылок для Src равен 2
//строка Dst изменилась и скопирована
//в другую область памяти. Значение
//счетчика Src уменьшилось на 1

Большие строки widest ring представляют собой последовательность 16- битовых символов UNICODE и во многом похожи на длинные строки Ansistring. Наиболее существенным недостатком таких строк является отсутствие счетчика ссылок. Это приводит к тому, что при любом присвоении одной строки другой необходимо выделять память и копировать строку в эту область памяти, что приводит к снижению производительности. Строки widestring легко преобразуются в Ansistring, и наоборот.
Эти действия выполняются компилятором при присвоении. Следующий фрагмент кода (листинг 6.32) показывает, как это делается.
Листинг 6.32. Взаимное преобразование строк Widestring и Ansistring
var
aString: String;
wString: WideString;
begin
wString := 'WideString to Ansistring conversion demo';
aString := wString; // преобразование WideString в Ansistring
aString := 'Ansistring to WideString conversion demo';
wString := aString; //преобразование Ansistring в WideString

Мы не будем рассматривать здесь строки widestring отдельно, поскольку в большинстве случаев манипуляции с ними аналогичны тем, которые выполняются для AnsiString. Рассмотрение применения больших строк для операций с многобайтовыми символами и последовательностями выходит за рамки тематики этой книги.
Еще один тип строк, который мы рассмотрим, — строки с завершающим нулем (null-terminated string). Эти строки представляют собой массивы символов, в которых первый символ имеет нулевое смещение. Такая строка не хранит размер, зато имеет завершающий символ 0. Такое представление строк является типичным для языка С. Строки с завершающим нулем широко используются при вызове функций WIN API (последние написаны на С).

Следует сказать, что длинные строки Delphi также имеют завершающий ноль, что делает их совместимыми со строками с завершающим нулем. Длинные строки можно преобразовать к строкам с завершающим нулем, приведя их к типу PChar. В наших последующих примерах мы будем использовать такую возможность.
Встроенный ассемблер позволяет выполнять практически любые сколь угодно сложные манипуляции со строками. Особенно эффективными являются операции над отдельными символами строки. В Delphi 7 имеется много встроенных процедур обработки строк, выполняющих копирование, выделение подстрок, конкатенацию (объединение). Несмотря на наличие таких процедур, на практике часто необходимо разрабатывать весьма специфические алгоритмы обработки, которые не могут быть эффективно реализованы в Delphi. Некоторые из таких алгоритмов, в которых используются процедуры на встроенном ассемблере, представлены в последующих примерах.

Начнем с примеров работы со строками с завершающим нулем. На практике часто приходится находить размер такой строки. Поместим на главную форму приложения два поля редактирования Edit с именами Editl и Edit2, две метки Label и кнопку Button. Исходный текст приложения представлен в листинге 6.33.
Листинг 6.33. Программа, вычисляющая размер строки с завершающим нулем unit sspas;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls,
Forms, Dialogs, StdCtrls;
type
Tforml = class(Tform)
Buttonl
Editl
Edit2
Labell
Label2
Tbutton;
Tedit;
Tedit;
Tlabel;
Tlabel;
procedure ButtonlClick(Sender: Tobject);
private
{ Private declarations }
public
{ Public declarations }
end;
Forml: TForml;
si: PChar;
lsl: Integer;
implementation
{$R *.dfm}
function NulTermLen(sl: PChar): Integer; stdcaii;
asm
push EDI
mov EDI, si
mov EDX, EDI
mov AL, 0
eld
@next:
scasb
jne @next
sub EDI, EDX
mov EAX, EDI
dec EAX
pop EDI
end;
478 Гпава 6
procedure TForml.ButtonlClick(Sender: TObject);
begin
si :='Hello from BASM!'#0;
Editl.Text := si;
lsl := NulTermLen(sl);
Edit2.Text := IntToStr(lsl);
end;
end.

Строка с завершающим нулем si определена как указатель типа PChar в секции объявления переменных, а инициализация выполняется в обработчике нажатия кнопки. Ассемблерная процедура NuiTermLen подсчитывает размер строки, принимая в качестве входного параметра ее адрес. Для операций сравнения каждого символа строки с нулем используется строковая команда scasb. Для ее выполнения требуется, чтобы в регистре AL находился символ, который необходимо найти, а в регистре E D I — адрес строки. Флаг направления устанавливается в положение 0 для инкремента адресов:
mov EDI, si
mov AL, 0
eld
@next:
scasb
jne @next

Если нулевой элемент не найден, то переходим к следующей итерации по команде условного перехода. В противном случае вычисляем размер строки как разность значений, находящихся в регистрах E D I И EDX. Регистр E D I содержит адрес, на 1 больший чем адрес обнаруженного нулевого элемента, а регистр EDX — адрес строки (указатель на первый элемент). Результирующее значение помещается в регистр E D I . Результат, уменьшенный на 1, помещается, как обычно, в регистр ЕАХ:
sub EDI, EDX
mov EAX, EDI
dec EAX


 
 
 

Библиотека программиста. 2009.
Администратор: admin@programmer-lib.ru