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

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

Жанры

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

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

Шрифт:

 StrDispose(P1);

 StrDispose(P2);

end;

В данном примере мы увидим надпись Не равно. Это происходит потому, что в этом случае сравниваются указатели, а не содержимое строк, а указатели здесь будут разные. Попытка сравнить строки с помощью оператора сравнения — весьма распространенная ошибка у начинающих. Для сравнения таких строк следует применять специальную функцию —

StrComp
. Следующий пример, на первый взгляд, в плане сравнения ничем не отличается от только что рассмотренного (листинг 3.20).

Листинг 3.20. Сравнение строк
типа
PChar
, заданных одинаковыми литералами

procedure TForm1.Button2Click(Sender: TObject);

var

 P1, P2: PChar;

begin

 P1 := 'Test';

 P2 := 'Test';

 if P1 = P2 then Label1.Caption := 'Равно'

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

end;

Разница только в том, что строки хранятся не в динамической памяти, a в сегменте кода. Тем не менее на экране появится надпись Равно. Это происходит, разумеется, не потому, что сравнивается содержимое строк, а потому, что в данном случае два указателя оказываются равными. Компилятор поступает достаточно интеллектуально: видя, что в разных местах указаны литералы с одинаковым значением, он выделяет для такого литерала место только один раз, а потом помещает в разные указатели один адрес. Поэтому сравнение дает правильный (с интуитивной точки зрения) результат.

Такое положение дел только запутывает ситуацию со сравнением

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

Раз уж мы столкнулись с такой особенностью компилятора, немного отвлечемся от сравнения строк и "копнем" этот вопрос немного глубже. В частности, выясним, распространяется ли "интеллект" компилятора на литералы типа

AnsiString
(листинг 3.21).

Листинг 3.21. Сравнение переменных типа
AnsiString
как указателей

procedure TForm1.Button3Click(Sender: TObject);

var

 S1, S2: string;

begin

 S1 := 'Test';

 S2 := 'Test';

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

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

end;

В этом примере на экран будет выведено Равно. Как мы видим, указатели равны, т.е. и здесь компилятор проявил "интеллект". 

Рассмотрим чуть более сложный случай (листинг 3.22).

Листинг 3.22. Сравнение переменных
AnsiString
и
PChar
как указателей

procedure TForm1.Button4Click(Sender: TObject);

var

 P: PChar;

 S: string;

var

 S := 'Test';

 P := 'Test';

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

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

end;

В этом случае указатели окажутся не равны. Действительно,

с формальной точки зрения литерал типа
AnsiString
отличается от литерала типа
PChar
: в нем есть счетчик ссылок (равный -1) и длина. Однако если забыть с существовании этой добавки, эти два литерала одинаковы: четыре значащих символа и один
#0
, т.е. компилятор, в принципе, мог бы обойтись одним литералом. Тем не менее на это ему "интеллекта" уже не хватило. Рассмотрим еще один пример: сравнение строк по указателям (листинг 3.23).

Листинг 3.23. Сравнение глобальных переменных типа
AnsiString
как указателей

var

 GS1, GS2: string;

procedure TForm1.Button5Click(Sender: TObject);

begin

 GS1 := 'Test';

 GS2 := 'Test';

 if Pointer(GS1) = Pointer(GS2) then Label1.Caption := 'Равно';

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

end;

Этот пример отличается от приведенного в листинге 3.21 только тем, что теперь переменные глобальные, а не локальные. Однако этого достаточно, чтобы результат оказался другим — на экране мы увидим надпись Не равно. Для глобальных переменных компилятор всегда создаст уникальный литерал, на обнаружение одинаковых литералов ему "интеллекта" не хватает. Более того, если поставить точки останова в методах

Button3Click
и
Button4Click
, легко убедиться, что указатель, который будет помещен в переменную 
S
в методе
Button4Click
, отличается от того, который будет помещен в переменные
S1
и
S2
в методе
Button3Click
, хотя литералы в обоих случаях одинаковые. Компилятор умеет обнаруживать равенство литералов типа
AnsiString
только в пределах одной функции.

Теперь посмотрим, что будет с глобальными переменными типа

PChar
при присваивании им одинакового литерала (листинг 3.24).

Листинг 3.24. Сравнение глобальных переменных типа
PChar

var

 GP1, GP2: PChar;

procedure TForm1.Button6Click(Sender: TObject);

begin

 GP1 := 'Test';

 GP2 := 'Test';

 if GP1 = GP2 then Label1.Caption := 'Равно'

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

end;

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

PChar
, которым присваиваются одинаковые литералы в разных функциях, как и переменные типа
AnsiString
, получат разные значения.

Но вернемся к сравнению строк. Как мы знаем, строки

AnsiString
сравниваются по значению, а
PChar
— по указателю. А что будет, если сравнить
AnsiString
с
PChar
? Ответ на этот вопрос даёт листинг 3.25.

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

Черный Маг Императора 6

Герда Александр
6. Черный маг императора
Фантастика:
юмористическое фэнтези
попаданцы
аниме
7.00
рейтинг книги
Черный Маг Императора 6

Оцифрованный. Том 1

Дорничев Дмитрий
1. Линкор Михаил
Фантастика:
боевая фантастика
попаданцы
аниме
5.00
рейтинг книги
Оцифрованный. Том 1

Кодекс Охотника. Книга XIV

Винокуров Юрий
14. Кодекс Охотника
Фантастика:
боевая фантастика
попаданцы
аниме
5.00
рейтинг книги
Кодекс Охотника. Книга XIV

Штуцер и тесак

Дроздов Анатолий Федорович
1. Штуцер и тесак
Фантастика:
боевая фантастика
альтернативная история
8.78
рейтинг книги
Штуцер и тесак

Я снова граф. Книга XI

Дрейк Сириус
11. Дорогой барон!
Фантастика:
боевая фантастика
попаданцы
аниме
5.00
рейтинг книги
Я снова граф. Книга XI

Болотник

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

Кодекс Крови. Книга III

Борзых М.
3. РОС: Кодекс Крови
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Кодекс Крови. Книга III

Жестокая свадьба

Тоцка Тала
Любовные романы:
современные любовные романы
4.87
рейтинг книги
Жестокая свадьба

Стеллар. Трибут

Прокофьев Роман Юрьевич
2. Стеллар
Фантастика:
боевая фантастика
рпг
8.75
рейтинг книги
Стеллар. Трибут

Голодные игры

Коллинз Сьюзен
1. Голодные игры
Фантастика:
социально-философская фантастика
боевая фантастика
9.48
рейтинг книги
Голодные игры

Последняя Арена 8

Греков Сергей
8. Последняя Арена
Фантастика:
боевая фантастика
рпг
5.00
рейтинг книги
Последняя Арена 8

Черный маг императора 2

Герда Александр
2. Черный маг императора
Фантастика:
юмористическая фантастика
попаданцы
аниме
6.00
рейтинг книги
Черный маг императора 2

Последний Паладин

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

Измена. Свадьба дракона

Белова Екатерина
Любовные романы:
любовно-фантастические романы
эро литература
5.00
рейтинг книги
Измена. Свадьба дракона