Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Начинающим";
Текущий архив: 2008.08.10;
Скачать: [xml.tar.bz2];

Вниз

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

 
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;
Скачать: [xml.tar.bz2];

Наверх




Память: 0.53 MB
Время: 0.007 c
15-1213437901
@!!ex
2008-06-14 14:05
2008.08.10
Дух времини(Zeitgeist)


1-1196461699
Flexer
2007-12-01 01:28
2008.08.10
Конструктор для элемента коллекции


6-1191845923
Greench
2007-10-08 16:18
2008.08.10
Интернет-пейджер


15-1211482317
AEN
2008-05-22 22:51
2008.08.10
Кто нибудь играл в Dune4?


10-1148311452
atruhin
2006-05-22 19:24
2008.08.10
Открытые массивы и IDispatch





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский