Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2008.08.10;
Скачать: CL | DM;

Вниз

Функции и ее результат.   Найти похожие ветки 

 
maxon   (2008-07-07 23:07) [0]

I)
Например, есть такая функция:

function SomeFunc: TSomeType;
begin
// Как правильно писать
// Так:
Result:= value;
// или так:
SomeFunc:= value;
end;

Как же, все таки, правильно? Работают оба, но в чем разница?

II)
И еще, можно ли (правильно ли) использовать Result или ИМЯ_ФУНКЦИИ для работы внутри самой функции как с обычной переменной:

function SomeFunc: TSomeType;
begin
// Например
// Так:
Result:= Result * 2;
// или так:
SomeFunc:= SomeFunc * 2; // хотя, это уже рекурсия
end;

Для примера, вот функция, которая работает правильно (во всяком случаем результат верный):

function CharCount( const S: AnsiString; C: Char ): Cardinal;
var  
 i:      Cardinal;
 iLen:   Cardinal;
begin
 Result:= 0;
 iLen:= Length( S );

 if iLen < 1 then Exit;

 for i:= 1 to iLen do
   if S[i] = C then
     Inc( Result ); // <-- Разумно ли делать так или лучше создать отдельную переменную?
end;

Все это я спрашиваю еще и потому, что функции, для которых я это спрашиваю должны максимально быстро обрабатывать полученные данные, но при этом не использовать ЛИШНИХ переменных.


 
McSimm ©   (2008-07-07 23:11) [1]


> Inc( Result ); // <-- Разумно ли делать так или лучше создать
> отдельную переменную?

Разумно. Это и есть отдельная переменная, специально для этих целей.


 
maxon   (2008-07-07 23:33) [2]

Нашел следующий ответ:
Переменная Result используется, чтобы хранить значение результата, возвращенное функцией.

Когда функция начинается, Delphi сам автоматически создает эту переменную. Она имеет тот же самый тип, как и возвращаемый тип функции. Результат может использоваться в функции повсюду, как будто она была явно объявлена.


И еще, как дальше объясняется писать Result вместо ИмяФункции это новый механизм возвращения значения.


 
@!!ex ©   (2008-07-07 23:41) [3]

> SomeFunc:= SomeFunc * 2; // хотя, это уже рекурсия

Так нельзя, потому что берется не значение, а вызывается опять функция.


> Result:= value;

Так можно. Result - это тоже самое, что если в старом паскале написать:
Function NewInc(value:integer = 1):integer;
var
 Result:integer;
begin
 Result:=Result+value;
 NewInc:=Result;
end;

ИМХО далеко не лучшая идея со стороны борланда, т.к. в ряде случаев лишняя переменная не нужна. А ручками создать переменную Result - не проблема. Я сейчас так на сях делаю:
cVector4f cVector4f::operator* (const cMatrix4x4 &M)
{
cVector4f Result;
Result.x = x*M._11+y*M._21+z*M._31+M._41;
Result.y = x*M._12+y*M._22+z*M._32+M._42;
Result.z = x*M._13+y*M._23+z*M._33+M._43;
Result.w = x*M._14+y*M._24+z*M._34+M._44;
return Result;
};


 
maxon   (2008-07-08 00:01) [4]

Думаю ответ исчерпывающий, Спасибо всем!!!


 
Ega23 ©   (2008-07-08 00:08) [5]


> ИМХО далеко не лучшая идея со стороны борланда, т.к. в ряде
> случаев лишняя переменная не нужна.


В этом ряде случаев можно воспользоваться var-параметром, ы?


 
Германн ©   (2008-07-08 00:12) [6]


> Ega23 ©   (08.07.08 00:08) [5]

Тогда уж уместнее воспользоваться out-параметром.


 
umbra ©   (2008-07-08 00:17) [7]


> Function NewInc(value:integer = 1):integer;
> var
>  Result:integer;
> begin
>  Result:=Result+value;
>  NewInc:=Result;
> end;

Ничего, что локальные переменные не инициализируюются?


 
McSimm ©   (2008-07-08 00:17) [8]

тогда процедурой нельзя будет пользоваться как функцией.


> в ряде случаев лишняя переменная не нужна.

не проверял, но уверен, что когда Result не используется, она и не создается.


 
maxon   (2008-07-08 00:20) [9]


> не проверял, но уверен, что когда Result не используется,
>  она и не создается.

А вот, стоит! Интересно все таки.


 
@!!ex ©   (2008-07-08 00:21) [10]

> [5] Ega23 ©   (08.07.08 00:08)

использование out или var перенесет переменную на сторону вызывающего и все.

Например расчет нормали:

Function Normal(a,b:vector):vector;
begin
 Result:=Normalize(CrossVectors(a,b));
end;

Здесь создается 3! переменных типа vector.
Хотя достаточно одного создания при перемножении векторов.


> [7] umbra ©   (08.07.08 00:17)

ночь уже... там еще одной переменной не хватает, к ней как раз value и надо прибавлять.


 
Ega23 ©   (2008-07-08 00:27) [11]


> Здесь создается 3! переменных типа vector.


3! - это "три" или шесть (три факториал)?

А если так
Function Normal(var a,b:vector):vector;


 
Германн ©   (2008-07-08 00:45) [12]


> @!!ex ©   (08.07.08 00:21) [10]
>
> > [5] Ega23 ©   (08.07.08 00:08)
>
> использование out или var перенесет переменную на сторону
> вызывающего и все.
>

Дык на стороне вызывающего и так уже создана переменная, которой присваивается результат функции. Не так ли?


 
@!!ex ©   (2008-07-08 00:53) [13]

> Function Normal(var a,b:vector):vector;

Это сути не меняет, если вектор - это массив байтов на 4 элемента, то тоже самое.


> [12] Германн ©   (08.07.08 00:45)

Не факт.
Ведь я результат той же функции Normal могу передать в другую функцию.
В случае использвания функции я сделаю просто:
SomeFunction(Normal(a,b));

А если процедура с результатом в параметрах, придется опять же заводить лишнюю переменную.

c:vector;

Normal(a,b,c);
SomeFunction(c);


 
@!!ex ©   (2008-07-08 00:55) [14]

к тому же бывают случаи, когда результат выполнения функции игнорируется. Не часто, но бывает.
А с out - не проигнорируешь.


> не проверял, но уверен, что когда Result не используется,
> она и не создается.

Если это действительно так, то я не прав.


 
Германн ©   (2008-07-08 01:34) [15]


> @!!ex ©


> > [12] Германн ©   (08.07.08 00:45)
>
> Не факт.
> Ведь я результат той же функции Normal могу передать в другую
> функцию.
>

Не факт. Не спорю. Но сей вариант не вписывается в ситуацию
> ИМХО далеко не лучшая идея со стороны борланда, т.к. в ряде
> случаев лишняя переменная не нужна.


> к тому же бывают случаи, когда результат выполнения функции
> игнорируется. Не часто, но бывает.
>

Бывают. Но в таких случаях часто стоит пересмотреть логику работы и либо заменить функцию процедурой, либо разделить код функции на две части. Я не против решения Борланда разрешить вызов функции как процедуры, но понимаю как это плохо для некоторых незрелых. :)


 
@!!ex ©   (2008-07-08 01:44) [16]

> [15] Германн ©   (08.07.08 01:34)
> незрелых. :)

Вызов функции как процедуры - это общепринятая практика.
Например, лично я использую часто эту возможность, когда нужно при чтении из файла какой-то блок проигнорировать.

Речь не о том, что Result - это совсем плохое решение.
Речь о том, что бывают случаи, когда лишняя переменная ненужна. И такие случаи часто встречаются.
Я почему об этом заговорил?
Когда пишешь много вычислений в реалтайме, когда функции постоянно друг друга вызывают, выделение памяти на лишнюю процедуру - может очень даже заметно снизить скорость. Особенно если сама функция - три строчки на ассемблере. Приходится переписывать все на асме... там то переменные не выделяются.


 
@!!ex ©   (2008-07-08 01:44) [17]

Кстати, я не прав. Зря клевещу на Борланда. Все отлично сделано.


 
@!!ex ©   (2008-07-08 01:47) [18]

Pascal:
Function Normal(const a,b:TVector):TVector;
begin
 Result:=Normalize(CrossVectors(a,b));
end;


Assembler(IDA Pro 5.2)
.text:00403904 sub_403904      proc near               ; CODE XREF: .itext:004040EFp
.text:00403904                 push    ebx
.text:00403905                 push    esi
.text:00403906                 push    edi
.text:00403907                 add     esp, 0FFFFFFF4h
.text:0040390A                 mov     edi, ecx
.text:0040390C                 mov     esi, edx
.text:0040390E                 mov     ebx, eax
.text:00403910                 mov     ecx, esp
.text:00403912                 mov     edx, esi
.text:00403914                 mov     eax, ebx
.text:00403916                 call    sub_4038A4
.text:0040391B                 mov     eax, esp
.text:0040391D                 mov     edx, edi
.text:0040391F                 call    sub_4038D8
.text:00403924                 add     esp, 0Ch
.text:00403927                 pop     edi
.text:00403928                 pop     esi
.text:00403929                 pop     ebx
.text:0040392A                 retn
.text:0040392A sub_403904      endp


C(HexRays 1.0)
int __cdecl sub_403904()
{
 sub_4038A4();
 return sub_4038D8();
}


Как видно, ни о какой переменной Result речи не идет.
Даже больше: параметры насквозь проходят.


 
@!!ex ©   (2008-07-08 01:48) [19]

Хотя, конечно, пример не показательный, т.к. все в регистрах помещается.


 
@!!ex ©   (2008-07-08 01:51) [20]

Function Test(const a,b,c,d,e,f,g,h,i,j,k:TVector):TVector;
begin
 Result:=Test2(a,b,c,d,e,f,g,h,i,j,k);
end;


int __stdcall sub_403848(int a1, int a2, int a3, int a4, int a5, int a6, int a7, int a8, int a9)
{
 return sub_40382C(a1, a2, a3, a4, a5, a6, a7, a8, a9);
}


Посыпаю голову пеплом...


 
Германн ©   (2008-07-08 02:12) [21]


> @!!ex ©   (08.07.08 01:44) [16]
>
> > [15] Германн ©   (08.07.08 01:34)
> > незрелых. :)
>
> Вызов функции как процедуры - это общепринятая практика.
>
> Например, лично я использую часто эту возможность, когда
> нужно при чтении из файла какой-то блок проигнорировать.
>
>

Надеюсь, ты в отличие от РА находишься в трезвой памяти.
То что ты, как и многие другие, часто используешь вызов функции как процедуры - это нормально. Но ты не "незрелый".


 
Григорьев Антон ©   (2008-07-08 08:39) [22]


> Result - это тоже самое, что если в старом паскале написать:
>
> Function NewInc(value:integer = 1):integer;
> var
>  Result:integer;
> begin
>  Result:=Result+value;
>  NewInc:=Result;
> end;

Result - это не совсем локальная переменная, это, скорее, неявный выходной параметр. Для типов с автоматической инициализацией и финализацией можно почувствовать разницу: http://www.rsdn.ru/article/Delphi/dynarrays.xml#ESHAC

> Как же, все таки, правильно? Работают оба, но в чем разница?

В старых версиях Паскаля не было псевдопеременной Result, там надо было присваивать значение через имя функции. В Delphi появился более удобный механизм присваивания через Result, но старый способ оставлен для совместимости с существующим кодом.


 
Германн ©   (2008-07-08 21:58) [23]


> В старых версиях Паскаля не было псевдопеременной Result

Ну это не совсем так. Во встроенном ассемблере можно было к этой переменной обратиться @Result. Но по-моему только если возвращаемый результат имел тип String.
Буквоед. :)


 
Игорь Шевченко ©   (2008-07-08 22:00) [24]

McSimm ©   (08.07.08 00:17) [8]


> не проверял, но уверен, что когда Result не используется,
>  она и не создается.


Создается компилятором


 
Amoeba ©   (2008-07-08 23:59) [25]


> Ну это не совсем так. Во встроенном ассемблере можно было
> к этой переменной обратиться @Result.


В TP до TP6 встроенного ассемблера еще не было.


 
Германн ©   (2008-07-09 01:48) [26]


> Amoeba ©   (08.07.08 23:59) [25]

Ой врёшь!


 
Anatoly Podgoretsky ©   (2008-07-09 10:09) [27]

Так и было - не было.
Выход TP6 послужил причиной для отказа от TASM


 
Amoeba ©   (2008-07-09 10:53) [28]


> Германн ©   (09.07.08 01:48) [26]
>
>
> > Amoeba ©   (08.07.08 23:59) [25]
>
> Ой врёшь!

Не вру. И за базар отвечаю.



Страницы: 1 вся ветка

Текущий архив: 2008.08.10;
Скачать: CL | DM;

Наверх




Память: 0.55 MB
Время: 0.028 c
15-1214223913
@!!ex
2008-06-23 16:25
2008.08.10
Ненене, Дэвид Блэйн, ненене!


9-1172925794
PARUS
2007-03-03 15:43
2008.08.10
"Игра" - потестите


15-1214153592
Raisa
2008-06-22 20:53
2008.08.10
C# - посоветуйте форум


15-1214169103
JetuS
2008-06-23 01:11
2008.08.10
Сниффер ICMP-пакетов


15-1214045614
easy(Moskow)
2008-06-21 14:53
2008.08.10
случайно попал в Москву