Читаем О чём не пишут в книгах по Delphi полностью

В четвертом случае литерал также хранится в сегменте кода, но работы с указателем уже нет. Этот литерал занимает там пять байтов: один байт на длину и четыре — на символы. Переменная S размешается в стеке, занимая там 256 байтов, а присваивание ей литерала — это копирование значения литерала из сегмента кода в область памяти, занятую переменной. Таким образом, в дальнейшем мы работаем не с константой в сегменте кода, а с ее копией в стеке, которую можно без проблем модифицировать.

В пятом случае мы получаем указатель на этот участок стека. Обратите внимание, что приведение типов в данном случае не работает: для записи в P адреса первого символа строки приходится использовать оператор получения адреса @. Модификация строки проходит, как и в предыдущем случае, успешно, но при присваивании выражения типа PChar свойству типа AnsiString длина строки определяется по правилам, принятым для PChar, т.е. строка сканируется до обнаружения нулевого символа. Но поскольку ShortString "не отвечает" за то, что будет содержаться в неиспользуемых символах, там может остаться всякий мусор от предыдущего использования стека. Никакой гарантии, что сразу после последнего символа будет #0, нет. Отсюда и появление непонятных символов на экране.

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

<p>3.3.3. Приведение литералов к типу <emphasis>PChar</emphasis></p>

В разд. 1.1.13 мы уже говорили, что когда у функции есть параметр типа PChar, и этот параметр не будет изменяться функцией, при вызове ей можно передавать строковый литерал (см. листинг 1.20). Компилятор размещает литерал в сегменте кода и передает функции указатель на эту память.

В примерах кода, приведенных на различных сайтах, можно нередко встретить такую ситуацию, когда литерал, передаваемый в качестве параметра типа PChar, явно приводится к этому типу. Разберемся, что это дает. Для этого положим на форму четыре кнопки и напишем в обработчиках их нажатия следующий код (листинг 3.18. пример PCharLit на компакт-диске).

Листинг 3.18. Приведение литералов к типу PChar

procedure TForm1.Button1Click(Sender: TObject);

begin

 Application.MessageBox('Text', nil, 0);

end;

procedure TForm1.Button2Click(Sender: TObject);

begin

 Application.MessageBox('A', nil, 0);

end;

procedure TForm1.Button3Click(Sender: TObject);

begin

 Application.MessageBox(PChar('Text'), nil, 0);

end;

procedure TForm1.Button4Click(Sender: TObject);

begin

 Application.MessageBox(PChar('A'), nil, 0);

end;

Метод TApplication.MessageBox по каким-то непонятным причинам имеет параметры типа PChar вместо string, и мы этим воспользуемся. При его вызове будет показано диалоговое окно с текстом, переданным в качестве первого параметра (в заголовке будет написано Ошибка, т.к. второй параметр у нас nil). Нажатие на первую и вторую кнопку не приводит ни к каким неожиданностям — мы видим на экране Text и А соответственно. Теперь перейдем к коду с явным приведением литерала к PChar. Нажатие на третью кнопку к сюрпризам не приведет, а вот нажатие на четвертую даст исключение Access violation.

Перейти на страницу:
Нет соединения с сервером, попробуйте зайти чуть позже