![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Строка, лучший способ сравнения
vadim83 © (2015-08-07 12:33:00)Друзья, вопрос из разряда понять, как оно "внутри" сравнивается/проверяется. Покажу на примере:
function (s: string): string;
begin
if s = '' then
Result := 'empty'
else
Result := DoSomething(s);
end;
Простая функция, коих найдется в каждом проекте. Вот мне интересно, как лучше/правильнее/быстрее проверить строку на "пустоту". Ведь есть вариант сравнить так:
function (s: string): string;
begin
if Length(s) = 0 then
Result := 'empty'
else
Result := DoSomething(s);
end;
Тип string имеет свой счетчик ссылок и длину строки, по идее второй вариант должен быть быстрее, но я не знаю как оно "под капотом" это проверяет, поскольку не силен в асме.
Еще догадываюсь, что т.н. пустота в выражении (s <> '') это тоже самое что сравнить с nil, но тут есть сомнения. Поясните пожалуйста эти моменты, у кого уже сложилась вся картинка.
Спасибо.
KSergey (2015-08-27 22:21:00) [1]Короче, рассказываю, я этот момент изучал когда-то.
Тогда мне думалось, что если я сделаю глобальную переменную на приложение
gEmptyStr := '';
и все присвоения, если мне понадобится пустая строка, или сравнения буду делать с ней - то всё будет клёво, у меня "один экземпляр пустой строки".
Так вот, самое быстрое - это именно простое
if s = '' then
В этом случае компилятор прямо по месту генерирует простейшие код почти одной командой, где просто фактически проверяет значение указателя строки на 0, т.к. компилятор знает, что пустые строки - это указатель равный 0. В общем про '' компилятор явно знает и отлично оптимизирует.
И "обнуление строки" (в смысле присваивание ей пустой строки) - это тоже прямо так и писать
str := '';
тогда компилятор просто освобождает память из-под строки и указателю на неё присваивает 0.
Если если делать как я (через гло. переменную) - то это вырождается в довольно длинный код, где берутся указатели на 2 сравнваемые строки, проветяется а не равен ли какой-то из них 0 н уи прочие вокруг этого свистопляски.
Если написать
if Length(s) = 0
то всё равно вызовется подпрограмма реализации _Length (что уже не быстро), в ней первым делом проверится "а не равно ли переданное значение указателя на строку 0, если равно - то результат функции 0 и выход", потом по возвращении мы результат сравниваем по написанному нами условию... короче снова свистопляска намного длиннее чем то, что генерирует компилятор для if s = ''.
han_malign (2015-08-12 13:21:00) [2]
> в [1] приведен пример
- а в [22] приведён ответ - для тех кто "не боится".
для особо "смелых"приведу код эквивалентный[1]
var s : string;
begin
s := '';
if _LStrToPChar(s) <> nil then
ShowMessage('А ты точно только только в асме не силен?')
end;
- самые бессстрашныемогут проверить, нажав в отладчике [Ctrl+Alt+C]...
кгшзх (2015-08-11 17:37:00) [3]не надо бояться.
в [1] приведен пример
han_malign (2015-08-11 10:35:00) [4]
> стринговая переменная или есть, или ее выбросил оптимизатор и ее нет вообще.
- боюсь Вы путаете понятия - переменная, константа и литерал...
А так же не можете отличить скалярныйтип от сложносоставного, и вряд ли сможете понять, что в Dephi словосочетание " магиякомпилятора" - это вполне официальный термин...
З.Ы. И как говорит Задорнов - "Я не знаю что сейчас с вами будет..." - есть еще ShortString - который - "страаашно сказааать..." - реализован совершенно по другому...
кгшзх (2015-08-10 18:05:00) [5]Если указатель равен nil, то FreeMem ничего не будет делать от слова вообще
зачем так долго тормозить?
стринговая переменная или есть, или ее выбросил оптимизатор и ее нет вообще.
если она не выброшена оптимизатором, память под нее распределена.
длина самой строки + 5 байт.
где тут нил?
при чем здесь Pointer(s) , если PChar не нил (самый первый пример)?
var i : integer;
i := 0;
Pointer(i) скажет что оно нил. Вы мне после этого скажете что значит и i в ниле?
icWasya (2015-08-10 16:58:00) [6]>[9]сделай мне переменную стринг чтобы она была в нил
Если переменная стрингявляется полем класса, то сразу после NewInstance она содержит как раз nil
> [11]
>var
>S: String;
>сразу после этого съедено пять байт минимум.
>при выходе из процы они будут освобождены.
>и если нет указателя или он нил, то как менеджер памяти будет чистить распределенное?
Во первых, даже если в S будет указатель на пустую строку, которая, внезапно не пять(длина строки-4 + завершающий байт-1) а девять(4+1+счётчик ссылок-4)(а в последних версиях еще +кодовая страница+размер элемента), то эта строка не выделяется из кучи, а находится в секции констант, и при выходе из функции не удаляется.
> как менеджер памяти будет чистить распределенное?
Если указатель равен nil, то FreeMem ничего не будет делать от слова вообще
han_malign (2015-08-10 14:30:00) [7]
>> причем тут "сделай мне переменную стринг чтобы она была в нил", дорогой?
> при том, дорогой.
- что магия на самом деле здесь
if PAnsiChar(s) <> nil then
удивись( D7модуль System):
function _LStrToPChar(const s: AnsiString): PChar;
{$IFDEF PUREPASCAL}
const
EmptyString = '';
begin
if Pointer(s) = nil then
Result := EmptyString
else
Result := Pointer(s);
end;
{$ELSE}
asm
{ -> EAX pointer to str }
{ <- EAX pointer to PChar }
TEST EAX,EAX
JE @@handle0
RET
{$IFDEF PIC}
@@handle0:
JMP PICEmptyString
{$ELSE}
@@zeroByte:
DB 0
@@handle0:
MOV EAX,offset @@zeroByte
{$ENDIF}
end;
{$ENDIF}
> попробуй по настоящему обмануть оптимизатор
{$O-}
vadim83 (2015-08-07 22:09:00) [8]Друзья, спасибо всем, разобрался. Sha, вам отдельное спасибо. Даже еще нашел инфу на стековерфлоу, народ там не поленился в еще и в асме все разложить)
Sha (2015-08-07 18:55:00) [9]>vadim83 (07.08.15 12:33)
Из описания формата представления строковых данных можно сделать вывод, что что пустую строку можно хранить двумя способами:
1. С нулевым указателем (и без данных).
2. С ненулевым указателем (и с данными нулевой длины).
Оба варианты ничему не противоречат. Однако в Delphi все внутренние процедуры работы со строками написаны таким образом, что как только они обнаруживают, что результатом операции будет пустая строка, то для представления результата используют только первый вариант хранения (с нулевым указателем).
Именно поэтому компилятор Delphi для проверки
if s='' then
имеет право использовать оптимизированный код вроде этого
if pointer(s)=nil then
Если ты в своих проектах будешь использовать функции работы со строками из пакетов сторонних производителей, то необходимо быть абсолютно уверенным, что они также следуют этому соглашению. Иначе для проверки на пустоту придется использовать сравнение вида
if Length(s)=0
которое хуже оптимизируется компилятором.
кгшзх (2015-08-07 16:52:00) [10]Удалено модератором
кгшзх (2015-08-07 16:51:00) [11]да пофик, дорогой, и этот пример.
попробуй по настоящему обмануть оптимизатор
Palladin (2015-08-07 16:49:00) [12]
> так вот внутри этой функции твой оптический обман не сработает.
татыче
procedure TForm11.Button1Click(Sender: TObject);
var
S: String;
begin
S := 'sdfasd';
ppp(S);
end;
procedure TForm11.ppp(var RR: String);
begin
RR := '';
if Pointer(RR) = nil then
ShowMessage('E');
end;
пока
Palladin (2015-08-07 16:48:00) [13]Удалено модератором
кгшзх (2015-08-07 16:47:00) [14]причем тут "сделай мне переменную стринг чтобы она была в нил", дорогой?
при том, дорогой.
кгшзх (2015-08-07 16:47:00) [15]кроме того, твой "Е" - побочный эффект оптимизатора.
ты же никуда не передаешь свою переменную, вот и в exe для нее никакого кода нет и пойнтер на ничего и показывает ничего.
а у нас тут на минуточку function (s: string): string;
в которой кое-когда, со строкой будет кое-что делаться.
так вот внутри этой функции твой оптический обман не сработает.
Palladin (2015-08-07 16:46:00) [16]
> кгшзх © (07.08.15 16:43) [11]
причем тут "сделай мне переменную стринг чтобы она была в нил", дорогой?
ты не мажся, на уровне кода никто не сможет string с nil сравнить
Palladin (2015-08-07 16:45:00) [17]да, btw, если присвоишь '' любой переменной string и сравнишь через каст, можешь еще раз исполнить дефекацию
кгшзх (2015-08-07 16:43:00) [18]При чем здесь пойнтер, дорогой?
var
S: String;
сразу после этого съедено пять байт минимум.
при выходе из процы они будут освобождены.
и если нет указателя или он нил, то как менеджер памяти будет чистить распределенное?
Palladin (2015-08-07 16:39:00) [19]
> кгшзх © (07.08.15 16:23) [9]
Можешь обкакаться от удивления
procedure TForm11.Button1Click(Sender: TObject);
var
S: String;
begin
if Pointer(S) = nil then
ShowMessage('E');
end;
кгшзх (2015-08-07 16:23:00) [20]В процедуре сравнения строк сначала проверяется равенство указателей - если оба Nil
сделай мне переменную стрингчтобы она была в нил
а потом пиши ерунду