Модераторы: Poseidon, Snowy, bems, MetalFan
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Использование UniqueString, вопрос по работе строками 
V
    Опции темы
cemick
Дата 26.12.2009, 11:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 416
Регистрация: 6.7.2006
Где: Санкт-Петербург

Репутация: 2
Всего: 6



Наткнулся на тему http://stackoverflow.com/questions/1951192...ing-var-strings

и вот такой пример
 
Код

procedure TForm5.btn1Click(Sender: TObject);
var s:sTRING;
begin
   s := 'var string';
   UniqueString(s);
   SetCaption(s);
   Caption := s;
end;

procedure TForm5.SetCaption(const Value: string);
var
  p: PChar;
begin
  p := PChar(Value);
  p[3] := '?';
  Caption := Value;
end;


Мне не совсем понятно, что происходит и почему комментирование строчки  UniqueString(s); приводит к ошибке:

 
Код

procedure TForm5.btn1Click(Sender: TObject);
var s:sTRING;
begin
   s := 'var string';
  // UniqueString(s);  <--- Комментируем
   SetCaption(s);
   Caption := s;
end;

procedure TForm5.SetCaption(const Value: string);
var
  p: PChar;
begin
  p := PChar(Value);
  p[3] := '?'; < -- Получаем ошибку AV
  Caption := Value;
end;


Как я понимаю UniqueString гарантирует уникальность строки, просто копируя AnsiString строку в памяти.  Const же параметр передается по ссылки, но компилятор следит за тем, что бы значение параметра не менялось и не передався ни кому указатель на строку, где она могла бы изменится. Не понятно, почему после UniqueString, константная строка ведет себя как объект. Вот как то так не понятно.
PM MAIL WWW   Вверх
Amphiluke
Дата 26.12.2009, 12:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


   ☽
***


Профиль
Группа: Завсегдатай
Сообщений: 1253
Регистрация: 26.8.2009

Репутация: 5
Всего: 112



Цитата(Delphi help)

When you cast a long-string expression to a pointer, the pointer should usually be considered read-only. You can safely use the pointer to modify the long string only when all of the following conditions are satisfied.

  •  The expression cast is a long-string variable.
  •  The string is not empty.
  •  The string is unique--that is, has a reference count of one. To guarantee that the string is unique, call the SetLength, SetString, or UniqueString procedure.
  •  The string has not been modified since the typecast was made.
  •  The characters modified are all within the string. Be careful not to use an out-of-range index on the pointer.



Так что, видимо, это не только UniqueString() касается.
Код

  SetString(s, PChar('foo bar baz'), Length('foo bar baz'));
  SetConstCaption(s);
  Caption := s;


PM   Вверх
cemick
Дата 26.12.2009, 14:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 416
Регистрация: 6.7.2006
Где: Санкт-Петербург

Репутация: 2
Всего: 6



UniqueString не просто копирует строку в памяти? А вносит какие то изменения, которые позволяют при 
 p := PChar(Value);
 p[3] := '?';

определить что это уникальная строка? Ведь после s := 'var string'; количество ссылок на s тоже равно 1. Чем тогда отличается s от того, что получаем после UniqueString (s)
PM MAIL WWW   Вверх
Amphiluke
Дата 26.12.2009, 15:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


   ☽
***


Профиль
Группа: Завсегдатай
Сообщений: 1253
Регистрация: 26.8.2009

Репутация: 5
Всего: 112



Запись
Код

s := 'var string';

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

Да, впрочем, что рассказывать: вот здесь почитайте.

Это сообщение отредактировал(а) Amphiluke - 26.12.2009, 15:27
PM   Вверх
cemick
Дата 26.12.2009, 15:41 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 416
Регистрация: 6.7.2006
Где: Санкт-Петербург

Репутация: 2
Всего: 6



Цитата(Amphiluke @  26.12.2009,  15:27 Найти цитируемый пост)
указывает компилятору разместить строковую константу в области сегмента кода, доступной только для чтения. Приведение типа к PChar не обеспечивает копирования строки из сегмента кода в динамическую память, а просто заносит указатель на константу в переменную типа PChar, поэтому попытка изменения строки приводит к AV.
А UniqueString как раз выполняет такое копирование в область памяти, доступную для изменения…

Да, впрочем, что рассказывать: вот здесь почитайте.

хм, как я понял из  
Цитата

В третьем случае константа, как и раньше, размещается в сегменте кода. Счётчик ссылок у таких констант всегда равен -1 — это значение указывает менеджеру памяти, что это константа, которая не может быть изменена и память для которой не нужно освобождать.

var s: String;
s := 'var string'; - это константа размещенная в сегменте кода и у нее число ссылок должно быть равным -1?

Смотрю количество ссылок:
PInteger(Integer(@s[1])-8)^

Получаю 1. Почему?
PM MAIL WWW   Вверх
Amphiluke
Дата 26.12.2009, 16:15 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


   ☽
***


Профиль
Группа: Завсегдатай
Сообщений: 1253
Регистрация: 26.8.2009

Репутация: 5
Всего: 112



А вы посмотрели 5-й пример? Указатель, полученный с применением оператора @ указывает на область памяти, доступной для изменения. Следовательно, счетчик ссылок не равен -1.

Попробуйте:
Код

ShowMessage(IntToStr(Integer(PInteger(Integer(PChar(s))-8)^)));

PM   Вверх
cemick
Дата 26.12.2009, 16:40 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 416
Регистрация: 6.7.2006
Где: Санкт-Петербург

Репутация: 2
Всего: 6



Цитата(Amphiluke @  26.12.2009,  16:15 Найти цитируемый пост)
А вы посмотрели 5-й пример? Указатель, полученный с применением оператора @ указывает на область памяти, доступной для изменения. Следовательно, счетчик ссылок не равен -1.

Попробуйте:
код Pascal/Delphi
1:
ShowMessage(IntToStr(Integer(PInteger(Integer(PChar(s))-8)^)));



UniqString_Const.pas.32: P := @s[1];
0045A856 8D45F8           lea eax,[ebp-$08]
0045A859 E8E2A4FAFF       call @UniqueStringA
0045A85E 8945F0           mov [ebp-$10],eax

Во как оказывается, теперь все встало на свои места. Спасибо!

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


PM MAIL WWW   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Delphi: Общие вопросы"
SnowyMetalFan
bemsPoseidon
Rrader

Запрещается!

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делиться вскрытыми компонентами

  • Литературу по Дельфи обсуждаем здесь
  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Вопросы по реализации алгоритмов рассматриваются здесь
  • 90% ответов на свои вопросы можно найти в DRKB (Delphi Russian Knowledge Base) - крупнейшем в рунете сборнике материалов по Дельфи


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Snowy, MetalFan, bems, Poseidon, Rrader.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Delphi: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.0464 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.