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

Вниз

Порядок вычисления аргументов в функции   Найти похожие ветки 

 
jack128 ©   (2004-09-17 00:59) [0]

Вот на какую вещь наткнулся, может кто не знает..

есть процедура:
procedure SameProc(i: Integer; b: Integer);
begin
....
end;

вызываем её: SameProc(SameFunc1() + SameFunc2(), SameFunc3() + SameFunc4())

Для меня казалось, само сабой разумеещемся, что сначала вычисляется выражение SameFunc1() + SameFunc2(), а уже потом SameFunc3() + SameFunc4().. А вот нет! Оказывается порядок вычисления аргументов в процедурах/функциях неопределен..
Это может привести вот к каким казусам:

function IIF(Condition: boolean; a, b: Integer): Integer;
begin
 if Condition then Result := a else Result := b;
end;
...
var
 IntegerArray: array of Integer;
begin
 SetLength(IntegerArray, 1);
 IntegerArray[0] := 10;
 SameVar := iif(Length(IntegerArray) > 1, IntegerArray[1], -1); // Ошибка выхода за границу массива..
end;


Вот такие дела..


 
DiamondShark ©   (2004-09-17 01:04) [1]

И это совершенно правильно.


 
Gero ©   (2004-09-17 01:06) [2]


> jack128 ©   (17.09.04 00:59)

А что не так?
Естественно, range check error.


 
DiamondShark ©   (2004-09-17 01:11) [3]

Хе... Порядок-то, конечно, неопределён, только вот в приведённом коде ошибка к порядку вовсе даже никакого отношения не имеет. Выражение IntegerArray[1] вызовет ошибку вне зависимости от того, каким по порядку оно будет вычислено.


 
jack128 ©   (2004-09-17 01:26) [4]

DiamondShark ©   (17.09.04 1:11) [3]
Хе, да пример глупый, уже понял :-))


 
Григорьев Антон ©   (2004-09-17 11:07) [5]

А такие фокусы компилятор вообще нередко выкидывает. Вот, например: http://www.delphikingdom.com/asp/viewitem.asp?catalogid=631
Жаль только, чёткой спецификации в хелпе нет.


 
Danilka ©   (2004-09-17 11:20) [6]

[5] Григорьев Антон ©   (17.09.04 11:07)
Это не фокусы, а единственно-правильное поведение. Откуда он знает что у тебя за функция? Конечно, ему надо сначала вычислить все параметры, и уже потом результаты передать в функцию.
И по твоей ссылке тоже есть комментарий в котором все нормально написано.


 
Григорьев Антон ©   (2004-09-17 11:29) [7]


> Danilka ©   (17.09.04 11:20) [6]

Ненормально не само поведение, а то, что это поведение не описывается в справке. Где Борланд написал, какой порядок вычисления операндов использует их компилятор? А при отсутствии спецификации любой баг - это фича (с) Юрий Зотов.


 
Verg ©   (2004-09-17 11:33) [8]

Calling conventions determine the order in which parameters are passed to the routine. They also affect the removal of parameters from the stack, the use of registers for passing parameters, and error and exception handling. The default calling convention is register.

The register and pascal conventions pass parameters from left to right; that is, the leftmost parameter is evaluated and passed first and the rightmost parameter is evaluated and passed last. The cdecl, stdcall, and safecall conventions pass parameters from right to left.
For all conventions except cdecl, the procedure or function removes parameters from the stack upon returning. With the cdecl convention, the caller removes parameters from the stack when the call returns.

The register convention uses up to three CPU registers to pass parameters, while the other conventions pass all parameters on the stack.
The safecall convention implements exception “firewalls.” On Windows, this implements interprocess COM error notification.


 
Verg ©   (2004-09-17 11:43) [9]


> jack128 ©   (17.09.04 00:59)


А твой случай с "выходом за границу" вообще не связан с порядком вычислений параметров.

Параметры проц/ф-ции будут вычеслены обязательно.

Этим объясняются, кстати, и неуместные/нелепые попытки иногда заменить С-вый оператор ?: ф-цией в Паскале...

с = a ? b/a : 0;


 
Григорьев Антон ©   (2004-09-17 11:56) [10]


> Verg ©   (17.09.04 11:33) [8]

Я имел ввиду другое. Если слагаемые требуют вычисления, где написано, какое слагаемое будет вычислено первым?


 
Игорь Шевченко ©   (2004-09-17 12:00) [11]

Григорьев Антон ©   (17.09.04 11:56) [10]


>  где написано, какое слагаемое будет вычислено первым?


Может быть, вот здесь: "that is, the leftmost parameter is evaluated and passed first and the rightmost parameter is evaluated and passed last."

Впрочем, все зависит от оптимизатора.


 
jack128 ©   (2004-09-17 12:01) [12]

Verg ©   (17.09.04 11:43) [9]
Да понял я, понял!! Уж в первых двух постах расписали. Дело не в этом, в [10]


 
Verg ©   (2004-09-17 12:02) [13]


> Если слагаемые требуют вычисления, где написано, какое слагаемое
> будет вычислено первым?


Это относится к порядку вычисления выражений, а не как не к subj.

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


 
Verg ©   (2004-09-17 12:06) [14]

Хотя, я бы не стал полагаться на какой-то определенны порядок в одноприоритетных операциях типа
a() + b()

Привык все доводить до очевидности....


 
DiamondShark ©   (2004-09-17 12:08) [15]

Побочный эффект функции -- личная забота программиста.


 
jack128 ©   (2004-09-17 12:17) [16]

Игорь Шевченко ©   (17.09.04 12:00) [11]

Так ведь напрактике наоборот, сначало вычисляется правый параметр, а потом левый. Даже без оптимизации
{$o-}
procedure Test(i, j: boolean);
begin
end;

function Func1(): boolean;
begin
 Result := MessageBox(Application.Handle, "Func1", nil, mb_okcancel) = mb_ok;
end;

function Func2(): boolean;
begin
 Result := MessageBox(Application.Handle, "Func2", nil, mb_okcancel) = mb_ok;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
 Test(Func1, Func2);
end;
{$o+}


 
Григорьев Антон ©   (2004-09-17 12:18) [17]


> Игорь Шевченко ©   (17.09.04 12:00) [11]


Игорь, там речь идёт о порядке вычисления параметров функций, а я спрашивал про порядок вычисления операндов выражения.


 
DiamondShark ©   (2004-09-17 12:34) [18]


> Григорьев Антон ©   (17.09.04 12:18) [17]

Если порядок вычисления особо не оговаривается в спецификации языка, это означает, что программист не имеет права делать о нём какие-либо предположения.


 
jack128 ©   (2004-09-17 13:03) [19]

Если говорить о порядке вычисления выражений, то тут интересно, для логических выражений этот порядок как раз таки оговаривается (например if Assigned(SameObj) and SameObj.SameBoolProp then) а вот для арифметич. операторов нет.. Почему такая непоследовательность - мне не понятно..


 
Verg ©   (2004-09-17 13:08) [20]


> Почему такая непоследовательность - мне не понятно..


Ничего, привыкнешь :))


 
MBo ©   (2004-09-17 13:12) [21]

в конференциях Borland ребята из TeamB писали, что несмотря на
"the leftmost parameter is evaluated and passed first", порядок вычисления параметров не гарантирован.

Однако параметры, передающиеся через стек, вычисляются раньше передающихся через регистры (при соглашении о вызове по умолчанию register) - что и логично - eax,edx,ecx, скорее всего, будут задействованы при вычислении параметров. Регистровые параметры передаются в моем случае (D6) в обратном порядке, что противоречит хелпу, а вот стековые - в соответствии с соглашением о вызове:

register 45321
cdecl,stdcall,safecall 54321
pascal 12345


procedure TForm1.Button12Click(Sender: TObject);
 function M(a: Integer): Integer;
 begin
   Memo1.Lines.Text := Memo1.Lines.Text + IntToStr(a);
   Result := a;
 end;
 procedure AA(a, b, c, d, e: Integer); safecall;
 begin
   Memo1.Lines.Add(IntToStr(a + b + c + d + e));
 end;
begin
 AA(M(1), M(2), M(3), M(4), M(5));
end;


 
DiamondShark ©   (2004-09-17 13:15) [22]


> jack128 ©   (17.09.04 13:03) [19]

Почему непоследовательность?
Фиксированный порядок вычисления логических выражений -- часть спецификации языка, его введение обосновано.



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

Форум: "Потрепаться";
Текущий архив: 2004.10.03;
Скачать: [xml.tar.bz2];

Наверх




Память: 0.5 MB
Время: 0.039 c
1-1095400949
Makhanev A.S.
2004-09-17 10:02
2004.10.03
Запустить файл ресурсов, не сохраняя его на диск?


14-1095385238
Думкин
2004-09-17 05:40
2004.10.03
С днем рождения! 17 сентября


1-1094662910
Davinchi
2004-09-08 21:01
2004.10.03
Создание компонента просмотра буфера обмена


14-1095240759
infom
2004-09-15 13:32
2004.10.03
Какой придумать логотип для программы ?


3-1094184007
Карелин Артем
2004-09-03 08:00
2004.10.03
В ожидании EVENT. Чем пользоваться?





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
Английский Французский Немецкий Итальянский Португальский Русский Испанский