Строковый зоопарк

Вопросы программирования на Free Pascal, использования компилятора и утилит.

Модератор: Модераторы

Re: Строковый зоопарк

Сообщение and » 26.08.2011 17:41:23

vada писал(а):Видимо всетаки проблемы не в зоопарке строк а в менеджере памяти.В JAVA я зачастую даже не парюсь с дистроями объектов.
Сборщик мусора с подсчётом ссылок - кажется, одна из самых дискутируемых тем. В FPC (и Delphi, если в новых версиях ничего радикально не поменялось) такое есть только для string'ов, открытых массивов (array of ...), интерфейсов и (если не ошибаюсь) variant'ов. Помню, на "Королевстве" кто-то даже выкладывал обвязку, реализующую такое для любых данных. Внутри всё было сделано через string.

Max Rusov писал(а):Но в DLL всегда лучше передавать PChar
Ура! ура! Я наконец услышан :-)
Max Rusov писал(а):Совместим - означает, что вы можете одному присвоить другой, а не писать все что Вам вздумается.
Значит, у нас немного разные понятия о совместимости. Я под этим понимаю использование данных одного типа в любом месте, где используются данные другого типа. В худшем случае, с явным приведением - чтоб компилятор не ругался. А то, о чём Вы говорите, так и называется - "совместимость по присваиванию".
Max Rusov писал(а):Если это Class
Это object, почти такой же, как в Вашем примере выше. Но с pChar'ом, а не string'ом внутри. Вроде бы, мы всё обсудили. А тут вдруг какой-то Class всплыл...
Max Rusov писал(а):Не знаю, поддерживает ли Object перегрузку операторов
Перегрузку поддерживает afaik любой тип:
Код: Выделить всё
Operator:=(src:integer):string;
Begin
  result:=IntToStr(src)
End;
Аватара пользователя
and
постоялец
 
Сообщения: 124
Зарегистрирован: 16.09.2009 17:11:01
Откуда: г. Гомель, Беларусь

Re: Строковый зоопарк

Сообщение Max Rusov » 26.08.2011 18:17:38

and писал(а):>Но в DLL всегда лучше передавать PChar
Ура! ура! Я наконец услышан :-)

Лучше использовать PChar, из соображений интероперабельности. Чтобы эту DLL можно было использовать в любых языках. Если это не принципиально, то прекрасно работает и string. Я активно использую - проблем нет.

and писал(а):Значит, у нас немного разные понятия о совместимости. Я под этим понимаю использование данных одного типа в любом месте, где используются данные другого типа.

Такого вообще не бывает. Это значит - что это один и тот же тип. :)
Max Rusov
постоялец
 
Сообщения: 191
Зарегистрирован: 25.04.2009 15:46:03

Re: Строковый зоопарк

Сообщение SII » 26.08.2011 18:27:54

Такого вообще не бывает. Это значит - что это один и тот же тип.


Бывает-бывает. Тип может быть разный, просто компилятор это может самостоятельно учитывать и генерировать правильный код для каждого случая, основываясь на реальном типе. Например, любой целочисленный тип независимо от размера и наличия знака может использоваться где угодно, где целочисленный тип вообще годится; тем не менее, это не означает, что это всегда один и тот же тип. Со строками можно было бы, в принципе, сделать то же самое, но это посложней задача, особенно если тянуть совместимость со всем и вся...
SII
новенький
 
Сообщения: 64
Зарегистрирован: 24.06.2007 17:15:09
Откуда: Зеленоград

Re: Строковый зоопарк

Сообщение Max Rusov » 26.08.2011 18:35:39

SII писал(а):любой целочисленный тип независимо от размера и наличия знака может использоваться где угодно, где целочисленный тип вообще годится

Не везде. Если функция принимает var A :Word, то передать туда Byte при всем желании нельзя. А если две сущности _полностью_ совпадают по всем свойствам - то это одна и та же сущность. Принцип утки.
Max Rusov
постоялец
 
Сообщения: 191
Зарегистрирован: 25.04.2009 15:46:03

Re: Строковый зоопарк

Сообщение SII » 26.08.2011 18:49:14

Ну, здесь "работает" уже не сам тип, а фактически указатель на него, причём приведение типов заставит компилятор "проглотить" переменную типа байт вместо слова (что это может привести к неправильной работе программы, в данном случае неважно: это забота программиста). Кроме того (и важнее в данном случае), что в подобных случаях есть совместимость "снизу вверх", хотя компилятор и ругается при отсутствии явного приведения типов: если в процедуру требуется передать указатель на байт, можно подсунуть и указатель на слово. То же самое, кстати, касается обычной арифметики, где правильный результат гарантируется лишь в случае, если операнды и результат имеют подходящие типы (Паскаль не осуществляет в такой ситуации по-настоящему жёсткий контроль типов, позволяя смешивать данные разных размеров, почему явное приведение не требуется, а вот результат может получиться и ошибочный, хотя, если не отключать предупреждения, то проблем можно избежать -- во всяком случае, в Дельфях). А вот строки в этом плане действительно несовместимы вообще: в зависимости от конкретного типа требуется применять разные подходы к работе с ними. Другое дело, что на PChar я бы плюнул, ведь на самом деле это никакая не строка, а указатель на символ, и, ИМХО, нет никакого смысла пытаться подогнать его под "настоящие" строки. Вот отсутствие полного единообразия в работе с реальными строками (типа невозможности обратиться к символу по индексу в AnsiString) точно является приличным недостатком.
SII
новенький
 
Сообщения: 64
Зарегистрирован: 24.06.2007 17:15:09
Откуда: Зеленоград

Re: Строковый зоопарк

Сообщение alexey38 » 27.08.2011 10:02:29

Мне кажется, что указанная в теме проблема с PChar решается следующим подходом:
1. Внутри программы использовать только String, так как он и безопасен, и работает намного быстрее, чем нуль-терминированные строки.
2. При вызове DLL использовать PChar, как указатель на строку String: Func(PChar(s))
3. В тексте DLL при необходимости обработки копировать в строку String содержимое переданное указателем PChar
Таким образом при передачи строк в DLL не требуется ни выделение памяти явным образом, ни ее освобождение.

Более сложная задача, если из DLL нужно вернуть сроку.
Если мы исходим из того, что DLL может быть написана на другом языке, чем основная программа, то отсюда вытекает обязательное требование: менеджеры памяти в основной программе и в DLL могут быть разными и несовместимыми. Соответственно память выделять нужно не в DLL, а в основной программе, передавая в DLL указатель на выделенную память и количество выделенной памяти. Выделять память в DLL нельзя, т.к. основная программа не сможет ее освободить. Если все же требуется выделить память в DLL, то для ее освобождение нужно будет вызвать другую функцию из DLL.

Исходя из перечисленных выше принципов вытекает то, что выделение и освобождение памяти должно выполняться примерно в одном и том же месте программы.
Логичнее для этого использовать StrAlloc, StrDispose, а если нужен дубликат то StrNew.

Если внутри программы есть необходимость использование библиотек (не DLL) с функциями передающих параметры через PChar, то лучше написать обертку такой библиотеке, чтобы в основной программе использовать только String, т.к. не факт что вы правильно определили способ освобождения памяти. И тогда проще подкорректировать обертку, чем искать баги во всем тексте программы.

P.S. Подавляющее число проблем с безопасностью операционных систем и браузеров связано с тем, что в языке C, C++ был применен худший из вариантов строк, а именно нуль-терминированные строки, не содержащие сведений о выделенной под нее память. Можно сказать, что если бы язык C, C++ не был изобретен, либо не получил бы распространения. А его бы место было занято Паскалем, то всех этих разговоров про безопасность, дрявость просто бы не шло в принципе. А индустрия бы сохранила сотни миллиардов или даже триллионы долларов (или иных денежных знаков).
alexey38
долгожитель
 
Сообщения: 1627
Зарегистрирован: 27.04.2011 19:42:31

Re: Строковый зоопарк

Сообщение and » 27.08.2011 15:26:07

Max Rusov писал(а):из соображений интероперабельности. Чтобы эту DLL можно было использовать в любых языках. Если это не принципиально
Это принципиально.
Max Rusov писал(а):Если функция принимает var A :Word, то передать туда Byte при всем желании нельзя.
Разве? По-моему, можно. А вот наоборот, действительно, нельзя без явного приведения типов (которое в общем случае приведёт к логической ошибке).
Более короткий тип прекрасно передаётся туда, где ждут более длинный.
Аватара пользователя
and
постоялец
 
Сообщения: 124
Зарегистрирован: 16.09.2009 17:11:01
Откуда: г. Гомель, Беларусь

Re: Строковый зоопарк

Сообщение alexs » 27.08.2011 18:43:20

alexey38 писал(а):Мне кажется, что указанная в теме проблема с PChar решается следующим подходом:

Хороший ответ.
Мне кажется - современные интерпретаторы совсем отучили программистов от основного правила - убирать за собой. А это полезно не только при программировании :D.

Логика однозначно должна быть такой, чтобы при работе с разными системами управления памятью ты должен сам управлять той памятью, которую выделил.
А если это не твоё - то и нефиг там рулить. Только читай.

А любое другое решение - это поиск приключений себе и окружающим.
Аватара пользователя
alexs
долгожитель
 
Сообщения: 4064
Зарегистрирован: 15.05.2005 23:17:07
Откуда: г.Ставрополь

Re: Строковый зоопарк

Сообщение SII » 27.08.2011 18:52:51

and писал(а): Max Rusov писал(а):Если функция принимает var A :Word, то передать туда Byte при всем желании нельзя.

Разве? По-моему, можно. А вот наоборот, действительно, нельзя без явного приведения типов (которое в общем случае приведёт к логической ошибке).
Более короткий тип прекрасно передаётся туда, где ждут более длинный.


Тут как раз Вы ошибаетесь. Сами подумайте: передаётся не значение, а адрес переменной. Переменная типа Byte вмещает только один байт данных, и запись в неё более крупной величины что-нибудь может затереть, поэтому компилятор просто обязан нецензурно выругаться при попытке подсунуть ему такую переменную. Что же касается передачи более крупной переменной (Word вместо Byte), то затирания никогда не произойдёт, однако, скорее всего, на выходе будет некая каша: процедура запишет лишь тот размер, на который она рассчитана, и часть значения переменной останется неизменённой. Поэтому передача по ссылке типа другого размера всегда должна сопровождаться руганью компилятора (в отличие от передачи по значению, где компилятор может не ругаться, едва завидев подобную конструкцию, а сначала проверить значение -- либо во время трансляции, если оно является константой, либо уже во время выполнения, сгенерировав соответствующий проверочный код).
SII
новенький
 
Сообщения: 64
Зарегистрирован: 24.06.2007 17:15:09
Откуда: Зеленоград

Re: Строковый зоопарк

Сообщение Шурик Сетевой » 29.08.2011 16:06:05

Для управления памятью между библиотеками есть правило:
Чистит память тот, кто ее выделяет

два варианта:
1. Если библиотека хочет отдать вам блок, то вы самостоятельно распределяете его, инициализируете и отдаете библиотеке, обычно при этом размер блока идет первым словом, чтобы библиотека поняла, сколько туда можно сложить, затем вы его читаете и чистите.
2. Если же библиотека сама отдает вам указатель на новый распределенный блок, то она должна публиковать и способ убить его. Обычно это пара функций, первая возвращает указатель и код возврата, вторая принимает утилизируемый указатель, пример в нокиевском SDK - CONAGetDeviceInfo и CONAFreeDeviceInfoStructure.

Эти в принципе кроссплатформенно и безопасно, поскольку сто лет как уже применяется в C. Но муторно.
Шурик Сетевой
новенький
 
Сообщения: 11
Зарегистрирован: 05.03.2009 21:42:42

Пред.

Вернуться в Free Pascal Compiler

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 6

Рейтинг@Mail.ru