Здесь A1
A2
— 3, т.e. интуитивно ожидаемые. Тем не менее полагаться на интуицию все же не стоит: в более сложных случаях она может подвести. Дело в том, что стандарт языка Паскаль разрешает разработчикам конкретной реализации языка самим выбирать порядок вычисления операндов [5]. Поэтому, даже если вам удалось добиться желаемого порядка вычисления, в следующих версиях Delphi (или при переносе на другую платформу) программа может начать работать неправильно. Таким образом, разработчик не имеет права делать какие-то предположения о том, в каком порядке будут вычисляться операнды, а когда изменение этого порядка может повлиять на результат, код должен быть написан таким образом, чтобы исключить эту возможность. В частности, пример со сложением должен быть переписан так (листинг 3.50).procedure TForm1.Button1Click(Sender: TObject);
var
A1, A2: Integer;
begin
X:= 2;
A1:= X;
Inc(A1, GetValueAndModifyX);
X:= 2;
A2:= GetValueAndModifyX;
Inc(A2, X);
Label1.Caption:= IntToStr(A1);
Label2.Caption:= IntToStr(A2);
end;
Такой код, несмотря на побочные эффекты функции GetValueAndModifyX
Другие компиляторы могут использовать иной порядок вычисления операндов. Так, FreePascal вычисляет их в том порядке, в каком они встречаются в выражении, т. е. в первом примере А1
А2
— 3.3.4.2. Зацикливание обработчика
Для демонстрации этого "подводного камня" нам потребуется проект, на форме которого находится компонент TUpDown
OnClick
(листинг 3.51, пример UpDownDlg на компакт-диске).OnClick
UpDown1
procedure TForm1.UpDown1Click(Sender: TObject; Button: TUDBtnType);
begin
Application.MessageBox('Text', 'Caption', MB_OK);
end;
Теперь, если запустить программу и нажать на верхнюю кнопку UpDown1
TUpDown
свойства Position
и Min
равны нулю, поэтому нажатие на нижнюю кнопку не приводит к изменению значения Position
, и событие OnClick
не возникает; если изменить значение свойства Min
или Position
, то тот же эффект будет наблюдаться и при нажатии на нижнюю кнопку). Если закрыть это окно, то щелчок мышью в любом месте формы снова приведет к срабатыванию события OnClick
и открытию окна, и так до бесконечности: любой щелчок по форме в любом ее месте будет снова и снова приводить к появлению сообщения. Эффект наблюдается и в том случае, когда вместо стандартного сообщения в обработчике показывается любая другая модальная форма. Кроме того, тот же эффект будет, и если использовать события OnChanging
или OnChangingEx
вместо OnClick
, но мы далее для определенности будем говорить только об OnClick
.Если этот код пройти по шагам в отладчике, то никакого зацикливания не возникает: OnClick
Причина этой проблемы в том, как VCL обрабатывает сообщения, которые система помещает в очередь. При нажатии на кнопку компонента TUpDown
WM_LBUTTONDOWN
и WM_NOTIFY
. Компонент TUpDown
по умолчанию имеет стиль csCaptureMouse
— это означает, что при обработке WM_LBUTTONDOWN
VCL захватывает мышь в монопольное пользование для данного компонента.