Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Строка, лучший способ сравнения


Страницы:   1 2

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

сделай мне переменную стрингчтобы она была в нил
а потом пиши ерунду


Страницы:   1 2

Наверх

Титульная страница Поиск, карта сайта Написать письмо