Чтение онлайн

на главную - закладки

Жанры

О чём не пишут в книгах по Delphi

Григорьев Антон Борисович

Шрифт:
Листинг 3.25. Сравнение переменных типа
AnsiString
и
PChar

procedure TForm1.Button7Click(Sender: TObject);

var

 P: PChar;

 S: string;

begin

 S := 'Test';

 P := 'Тest';

 it S = Р then Label1.Caption := 'Равно'

 else Label1.Caption := 'Не равно';

end;

Этот код выдаст Равно. Как мы знаем

из предыдущих примеров (см. листинг 3.22), значения указателей не будут равны, следовательно, производится сравнение по содержанию, т.е. именно то, что к требуется. Если исследовать код, который генерирует компилятор, то можно увидеть, что сначала неявно создается строка
AnsiString
, в которую копируется содержимое строки
PChar
, а потом сравниваются две строки
AnsiString
. Сравниваются, естественно, по значению.

Для строк

ShortString
сравнение указателей невозможно, две таких строки всегда сравниваются по значению. Правила хранения литералов и сравнения с другими типами следующие:

1. Литералы типа

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

2. При сравнении строк

ShortString
и
AnsiString
первая сначала конвертируется в тип
AnsiString
, а потом выполняется сравнение.

3. При сравнении строк

ShortString
и
PChar
строка
PChar
конвертируется в
ShortString
, затем эти строки сравниваются.

Последнее правило таит в себе «подводный камень», который иллюстрируется следующим примером (листинг 3.26).

Листинг 3.26. Ошибка при сравнении переменных типа
ShortString
и
PChar

procedure TForm1.Button8Click(Sender: TObject);

var

 P: PChar;

 S: ShortString

begin

 P := StrAlloc(300);

 FillChar(P^, 299, 'A');

 P[299] := #0;

 S[0] := #255;

 FillChar(S[1], 255, 'A');

 if S = P then Label1.Caption := 'Равно'

 else Label1.Caption := 'Не равно';

 StrDispose(Р);

end;

Здесь формируется строка типа

PChar
, состоящая из 299 символов "A". Затем формируется строка
ShortString
, состоящая из 255 символов "А". Очевидно, что эти строки не равны, потому что имеют разную длину. Тем не менее на экране появится надпись Равно.

Происходит это вот почему: строка

PChar
оказывается больше, чем максимально допустимый размер строки
ShortString
. Поэтому при конвертировании лишние символы просто отбрасываются. Получается строка длиной 255 символов, совпадающая со строкой
ShortString
, с которой мы ее сравниваем. Отсюда вывод: если строка
ShortString
содержит 255 символов, а строка
PChar
— более 255 символов, и ее первые 255 символов совпадают с символами строки
ShortString
, операция сравнения ошибочно даст положительный результат, хотя эти строки не равны.

Избежать этой ошибки поможет либо явное сравнение длины перед сравнением строк, либо приведение одной из сравниваемых строк к

типу
AnsiString
(второй аргумент при этом также будет приведен к этому типу). Следующий пример (листинг 3.27) дает правильный результат Не равно.

Листинг 3.27. Правильное сравнение переменных типа
ShortString
и
PChar

procedure TForm1.Button9Click(Sender: TObject);

var

 P: PChar;

 S: ShortString;

begin

 P := StrAlloc(300);

 FillChar(P^, 299, 'A');

 P[299] := #0;

 S[0] := #255;

 FillChar(S[1], 255, 'A');

 if string(S) = P then Label1.Caption := 'Равно'

 else Label1.Caption := 'He равно';

 StrDispose(P);

end;

Учтите, что конвертирование в

AnsiString
— операция дорогостоящая в смысле процессорного времени (в этом примере будут выделены, а потом освобождены два блока памяти), поэтому там, где нужна производительность, целесообразнее вручную сравнить длину, а еще лучше вообще по возможности избегать сравнения строк разных типов, т.к. без конвертирования это в любом случае не обходится.

Теперь зададимся глупым, на первый взгляд, вопросом: если мы приведем строку

AnsiString
к
PChar
, будут ли равны указатели? Проверим это (листинг 3.28).

Листинг 3.28. Равенство указателей после приведения
AnsiString
к
PChar

procedure TForm1.Button10Click(Sender: TObject);

var

 S: string;

 P: PChar;

begin

 S := 'Test';

 P := PChar(S);

 if Pointer(S) = P then Label1.Caption := 'Равно'

 else Label1.Caption := 'Не равно';

end;

Вполне ожидаемый результат — Равно. Можно, например, перенести строку из сегмента кода в динамическую память с помощью

UniqueString
— результат не изменится. Однако выводы делать рано. Рассмотрим следующий пример (листинг 3.29).

Листинг 3.29. Сравнение указателя после приведения пустой строки к
PChar

procedure TForm1.Button11Click(Sender: TObject);

var

 S: string;

 P: PChar;

begin

 S := '';

 P := PChar(S);

 if Pointer(S) = P then Label1.Caption : = 'Равно'

 else Label1.Caption := 'He равно';

end;

От предыдущего он отличается только тем, что строка

S
имеет пустое значение. Тем не менее на экране мы увидим Не равно. Связано это с тем, что приведение строки
AnsiString
к типу
PChar
на самом деле не является приведением типов. Это скрытый вызов функции
_LStrToPChar
, и сделано так для того, чтобы правильно обрабатывать пустые строки.

Поделиться:
Популярные книги

Белые погоны

Лисина Александра
3. Гибрид
Фантастика:
фэнтези
попаданцы
технофэнтези
аниме
5.00
рейтинг книги
Белые погоны

Черный дембель. Часть 1

Федин Андрей Анатольевич
1. Черный дембель
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Черный дембель. Часть 1

Лишняя дочь

Nata Zzika
Любовные романы:
любовно-фантастические романы
8.22
рейтинг книги
Лишняя дочь

Темный Лекарь 5

Токсик Саша
5. Темный Лекарь
Фантастика:
фэнтези
аниме
5.00
рейтинг книги
Темный Лекарь 5

Последний из рода Демидовых

Ветров Борис
Фантастика:
детективная фантастика
попаданцы
аниме
5.00
рейтинг книги
Последний из рода Демидовых

Чиновникъ Особых поручений

Кулаков Алексей Иванович
6. Александр Агренев
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Чиновникъ Особых поручений

Попаданка в академии драконов 4

Свадьбина Любовь
4. Попаданка в академии драконов
Любовные романы:
любовно-фантастические романы
7.47
рейтинг книги
Попаданка в академии драконов 4

Боги, пиво и дурак. Том 6

Горина Юлия Николаевна
6. Боги, пиво и дурак
Фантастика:
фэнтези
попаданцы
5.00
рейтинг книги
Боги, пиво и дурак. Том 6

Курсант: Назад в СССР 10

Дамиров Рафаэль
10. Курсант
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Курсант: Назад в СССР 10

Сделай это со мной снова

Рам Янка
Любовные романы:
современные любовные романы
5.00
рейтинг книги
Сделай это со мной снова

Болотник 2

Панченко Андрей Алексеевич
2. Болотник
Фантастика:
попаданцы
альтернативная история
6.25
рейтинг книги
Болотник 2

Камень Книга двенадцатая

Минин Станислав
12. Камень
Фантастика:
боевая фантастика
городское фэнтези
аниме
фэнтези
5.00
рейтинг книги
Камень Книга двенадцатая

Небо для Беса

Рам Янка
3. Самбисты
Любовные романы:
современные любовные романы
5.25
рейтинг книги
Небо для Беса

Надуй щеки! Том 4

Вишневский Сергей Викторович
4. Чеболь за партой
Фантастика:
попаданцы
уся
дорама
5.00
рейтинг книги
Надуй щеки! Том 4