Форум: "Начинающим";
Текущий архив: 2017.04.16;
Скачать: [xml.tar.bz2];
ВнизСтрока, лучший способ сравнения Найти похожие ветки
← →
vadim83 (2015-08-07 12:33) [0]Друзья, вопрос из разряда понять, как оно "внутри" сравнивается/проверяется. Покажу на примере:
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, но тут есть сомнения. Поясните пожалуйста эти моменты, у кого уже сложилась вся картинка.
Спасибо.
← →
кгшзх © (2015-08-07 12:45) [1]
var s : string;
begin
s := "";
if PAnsiChar(s) <> nil then
ShowMessage("А ты точно только только в асме не силен?")
end;
← →
vadim83 (2015-08-07 12:55) [2]
> кгшзх ©
Т.е. по вашему это самый быстрый и лучший вариант?
ps: в изящных остротах тоже не силен, согласен)
← →
vadim83 (2015-08-07 12:58) [3]
> if PAnsiChar(s) <> nil then
мне казалось, что если s содержит первым символом #0, а потом другие символы, то ваше преобразование отработает неверно.
← →
кгшзх © (2015-08-07 13:08) [4]Т.е. по вашему это самый быстрый и лучший вариант?
по нашему пустая строка это не нил. больше ничего не имелось ввиду.
мне казалось, что если
ну ты же вроде умный.
знаешь что в строке есть и счетчик и длина.
но если строка указывает на нил, то кто и как сможет проверить (по какому етиамать адресу)
что длина нулевая и счетчик нулевой?
← →
кгшзх © (2015-08-07 13:17) [5]мне казалось, что если s содержит первым символом #0, а потом другие символы, то ваше преобразование отработает неверно.
а то что под буфер с нулевыми байтами внутри использовать тип string
и непарясь при этом ни о чем
размышлять о длинах строк - это тебе не казалось чудаковатым?
← →
Dimka Maslov © (2015-08-07 13:17) [6]Если @S[1] <> nil, то пустота строки проверяется проверкой длины строки, которая записана в двойном слове, расположенном до первого символа. Если же @S[1] = nil, следовательно строка пустая. Так в любом случае происходят обе проверки
← →
кгшзх © (2015-08-07 13:50) [7]
var pb, pb1 : PByte;
begin
GetMem(pb, 10); //берем 10 байт
ZeroMemory(pb,10); //обнуляем все 10
pb1 := pb;
inc(pb1); //нацеливаемся на второй слева
pb1^ := ord("A"); //пишем в него "другие символы"
if PChar(pb) <> nil then ShowMessage("Ку-ку!");
← →
icWasya © (2015-08-07 15:46) [8]В процедуре сравнения строк сначала проверяется равенство указателей - если оба Nil - то строки равны. Если Nil - только один, то проверяется длина второго. Если там ноль, то строки равны, елли нет-то этот другой больше. Если оба не Nil-То делается ещё куча проверок.
Так что сравнивать с Nil будет быстрее.
← →
кгшзх © (2015-08-07 16:23) [9]В процедуре сравнения строк сначала проверяется равенство указателей - если оба Nil
сделай мне переменную стринг чтобы она была в нил
а потом пиши ерунду
← →
Palladin © (2015-08-07 16:39) [10]
> кгшзх © (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:43) [11]При чем здесь пойнтер, дорогой?
var
S: String;
сразу после этого съедено пять байт минимум.
при выходе из процы они будут освобождены.
и если нет указателя или он нил, то как менеджер памяти будет чистить распределенное?
← →
Palladin © (2015-08-07 16:45) [12]да, btw, если присвоишь "" любой переменной string и сравнишь через каст, можешь еще раз исполнить дефекацию
← →
Palladin © (2015-08-07 16:46) [13]
> кгшзх © (07.08.15 16:43) [11]
причем тут "сделай мне переменную стринг чтобы она была в нил", дорогой?
ты не мажся, на уровне кода никто не сможет string с nil сравнить
← →
кгшзх © (2015-08-07 16:47) [14]кроме того, твой "Е" - побочный эффект оптимизатора.
ты же никуда не передаешь свою переменную, вот и в exe для нее никакого кода нет и пойнтер на ничего и показывает ничего.
а у нас тут на минуточку function (s: string): string;
в которой кое-когда, со строкой будет кое-что делаться.
так вот внутри этой функции твой оптический обман не сработает.
← →
кгшзх © (2015-08-07 16:47) [15]причем тут "сделай мне переменную стринг чтобы она была в нил", дорогой?
при том, дорогой.
← →
Palladin © (2015-08-07 16:48) [16]Удалено модератором
← →
Palladin © (2015-08-07 16:49) [17]
> так вот внутри этой функции твой оптический обман не сработает.
татыче
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;
пока
← →
кгшзх © (2015-08-07 16:51) [18]да пофик, дорогой, и этот пример.
попробуй по настоящему обмануть оптимизатор
← →
кгшзх © (2015-08-07 16:52) [19]Удалено модератором
← →
Sha © (2015-08-07 18:55) [20]>vadim83 (07.08.15 12:33)
Из описания формата представления строковых данных можно сделать вывод, что что пустую строку можно хранить двумя способами:
1. С нулевым указателем (и без данных).
2. С ненулевым указателем (и с данными нулевой длины).
Оба варианты ничему не противоречат. Однако в Delphi все внутренние процедуры работы со строками написаны таким образом, что как только они обнаруживают, что результатом операции будет пустая строка, то для представления результата используют только первый вариант хранения (с нулевым указателем).
Именно поэтому компилятор Delphi для проверкиif s="" then
имеет право использовать оптимизированный код вроде этогоif pointer(s)=nil then
Если ты в своих проектах будешь использовать функции работы со строками из пакетов сторонних производителей, то необходимо быть абсолютно уверенным, что они также следуют этому соглашению. Иначе для проверки на пустоту придется использовать сравнение видаif Length(s)=0
которое хуже оптимизируется компилятором.
← →
vadim83 (2015-08-07 22:09) [21]Друзья, спасибо всем, разобрался. Sha, вам отдельное спасибо. Даже еще нашел инфу на стековерфлоу, народ там не поленился в еще и в асме все разложить)
← →
han_malign © (2015-08-10 14:30) [22]
>> причем тут "сделай мне переменную стринг чтобы она была в нил", дорогой?
> при том, дорогой.
- что магия на самом деле здесь
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-}
← →
icWasya © (2015-08-10 16:58) [23]>[9]сделай мне переменную стринг чтобы она была в нил
Если переменная стринг является полем класса, то сразу после NewInstance она содержит как раз nil
> [11]
>var
>S: String;
>сразу после этого съедено пять байт минимум.
>при выходе из процы они будут освобождены.
>и если нет указателя или он нил, то как менеджер памяти будет чистить распределенное?
Во первых, даже если в S будет указатель на пустую строку, которая, внезапно не пять(длина строки-4 + завершающий байт-1) а девять(4+1+счётчик ссылок-4)(а в последних версиях еще +кодовая страница+размер элемента), то эта строка не выделяется из кучи, а находится в секции констант, и при выходе из функции не удаляется.
> как менеджер памяти будет чистить распределенное?
Если указатель равен nil, то FreeMem ничего не будет делать от слова вообще
← →
кгшзх © (2015-08-10 18:05) [24]Если указатель равен nil, то FreeMem ничего не будет делать от слова вообще
зачем так долго тормозить?
стринговая переменная или есть, или ее выбросил оптимизатор и ее нет вообще.
если она не выброшена оптимизатором, память под нее распределена.
длина самой строки + 5 байт.
где тут нил?
при чем здесь Pointer(s) , если PChar не нил (самый первый пример)?
var i : integer;
i := 0;
Pointer(i) скажет что оно нил. Вы мне после этого скажете что значит и i в ниле?
← →
han_malign © (2015-08-11 10:35) [25]
> стринговая переменная или есть, или ее выбросил оптимизатор и ее нет вообще.
- боюсь Вы путаете понятия - переменная, константа и литерал...
А так же не можете отличить скалярный тип от сложносоставного, и вряд ли сможете понять, что в Dephi словосочетание "магия компилятора" - это вполне официальный термин...
З.Ы. И как говорит Задорнов - "Я не знаю что сейчас с вами будет..." - есть еще ShortString - который - "страаашно сказааать..." - реализован совершенно по другому...
← →
кгшзх © (2015-08-11 17:37) [26]не надо бояться.
в [1] приведен пример
← →
han_malign © (2015-08-12 13:21) [27]
> в [1] приведен пример
- а в [22] приведён ответ - для тех кто "не боится".
для особо "смелых" приведу код эквивалентный [1]var s : string;
begin
s := "";
if _LStrToPChar(s) <> nil then
ShowMessage("А ты точно только только в асме не силен?")
end;
- самые бессстрашные могут проверить, нажав в отладчике [Ctrl+Alt+C]...
← →
KSergey © (2015-08-27 22:21) [28]Короче, рассказываю, я этот момент изучал когда-то.
Тогда мне думалось, что если я сделаю глобальную переменную на приложение
gEmptyStr := "";
и все присвоения, если мне понадобится пустая строка, или сравнения буду делать с ней - то всё будет клёво, у меня "один экземпляр пустой строки".
Так вот, самое быстрое - это именно простое
if s = "" then
В этом случае компилятор прямо по месту генерирует простейшие код почти одной командой, где просто фактически проверяет значение указателя строки на 0, т.к. компилятор знает, что пустые строки - это указатель равный 0. В общем про "" компилятор явно знает и отлично оптимизирует.
И "обнуление строки" (в смысле присваивание ей пустой строки) - это тоже прямо так и писать
str := "";
тогда компилятор просто освобождает память из-под строки и указателю на неё присваивает 0.
Если если делать как я (через гло. переменную) - то это вырождается в довольно длинный код, где берутся указатели на 2 сравнваемые строки, проветяется а не равен ли какой-то из них 0 н уи прочие вокруг этого свистопляски.
Если написать
if Length(s) = 0
то всё равно вызовется подпрограмма реализации _Length (что уже не быстро), в ней первым делом проверится "а не равно ли переданное значение указателя на строку 0, если равно - то результат функции 0 и выход", потом по возвращении мы результат сравниваем по написанному нами условию... короче снова свистопляска намного длиннее чем то, что генерирует компилятор для if s = "".
Страницы: 1 вся ветка
Форум: "Начинающим";
Текущий архив: 2017.04.16;
Скачать: [xml.tar.bz2];
Память: 0.53 MB
Время: 0.002 c