Форум: "Потрепаться";
Текущий архив: 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.041 c