3.4.1. Порядок вычисления операндов
3.4.1. Порядок вычисления операндов
Эта проблема связана с тем, что у человека есть определенные интуитивные представления о порядке выполнения действий программой, однако компилятор не всегда им соответствует. Рассмотрим следующий код (листинг 3.47, пример OpOrder на компакт-диске).
Листинг 3.47. "Неправильный" порядок вычисления операндов
var
X: Integer;
function GetValueAndModifyX: Integer;
begin
X:= 1;
Result:= 2;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
A1, A2: Integer;
begin
X:= 2;
A1:= X + GetValueAndModifyX;
X:= 2;
А2:= GetValueAndModifyX + X;
Label1.Caption:= IntToStr(A1);
Label2.Caption:= IntToStr(A2);
end;
Суть этого примера заключается в том, что функция GetValueAndModifyX имеет побочный эффект — изменяет значение глобальной переменной X. И эту же переменную мы используем при вычислении выражения, в которое входит также вызов GetValueAndModifyX. При вычислении A1 в выражении сначала упоминается X, а потом GetValueAndModifyX, при вычислении А2 — наоборот. Логично было бы предположить, что A1 получит значение 4, А2 — 3, т. к. вычисление первого операнда должно выполняться раньше второго. В действительности же обе переменные получат значение 3, поскольку компилятор сам выбирает порядок вычисления операндов независимо от того, в каком порядке они упоминаются в выражении. То же самое касается любых коммутативных операций: умножения, арифметических and, or и xor. Посмотрим, что будет для некоммутативных операций, например, для деления (листинг 3.48).
Листинг 3.48. "Неправильный" порядок вычисления операндов при делении
procedure TForm1.Button2Click(Sender: TObject);
var
A1, A2: Extended;
begin
X:= 2;
A1:= X / GetValueAndModifyX;
X:= 2;
A2:= GetValueAndModifyX / X;
Label1.Caption:= FloatToStr(A1);
Label2.Caption:= FloatToStr(A2);
end;
В результате выполнения этого кода A1 получает значение 0.5, A2 — 2, т. е. и здесь сначала вычисляется функция, а потом берется значение переменной X.
Если бы функция GetValueAndModifyX не имела побочных эффектов (т. е. только возвращала бы результат и больше ничего не меняла), порядок вычисления аргументов был бы нам безразличен. Вообще, функции, имеющие побочные эффекты, считаются потенциальным источником ошибок, поэтому их написание нежелательно. Но в некоторых случаях (например, в функции Random) обойтись без побочных эффектом невозможно.
Примечание
Побочные эффекты в функциях настолько небезопасны, что в некоторых языках они полностью запрещены. Например, в Аде изменять значения глобальных переменных могут только процедуры, но не функции.
Ради интереса посмотрим, что будет, если вторым аргументом тоже будет функция, зависящая от X, (листинг 3.49).
Листинг 3.49. Сложение двух операндов с побочными эффектами
function GetX: Integer;
begin
Result:= X;
end;
procedure TForm1.Button3Click(Sender: TObject);
var
A1, A2: Integer;
begin
X:= 2;
A1:= GetX + GetValueAndModifyX;
X:= 2;
A2:= GetValueAndModifyX + GetX;
Label1.Caption:= IntToStr(A1);
Label2.Caption:= IntToStr(A2);
end;
Здесь A1 получит значение 4, A2 — 3, т.e. интуитивно ожидаемые. Тем не менее полагаться на интуицию все же не стоит: в более сложных случаях она может подвести. Дело в том, что стандарт языка Паскаль разрешает разработчикам конкретной реализации языка самим выбирать порядок вычисления операндов [5]. Поэтому, даже если вам удалось добиться желаемого порядка вычисления, в следующих версиях Delphi (или при переносе на другую платформу) программа может начать работать неправильно. Таким образом, разработчик не имеет права делать какие-то предположения о том, в каком порядке будут вычисляться операнды, а когда изменение этого порядка может повлиять на результат, код должен быть написан таким образом, чтобы исключить эту возможность. В частности, пример со сложением должен быть переписан так (листинг 3.50).
Листинг 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 получит значение 4, А2 — 3.
Более 800 000 книг и аудиокниг! 📚
Получи 2 месяца Литрес Подписки в подарок и наслаждайся неограниченным чтением
ПОЛУЧИТЬ ПОДАРОКДанный текст является ознакомительным фрагментом.
Читайте также
Оптимизируем вычисления
Оптимизируем вычисления Google Gears ( http://gears.google.com/ ) обеспечивает выполнение напряженных вычислений без двух вышеоговоренных ограничений. Однако в общем случае нельзя полагаться на наличие Gears (в будущем было бы замечательно, чтобы решение по типу Gears WorkerPool API стало частью
Сетевые вычисления
Сетевые вычисления В компьютерной индустрии любят революции. В центре внимания постоянно находятся принципиально новые модели вычислений. Газеты, журналы, консультанты и эксперты до небес превозносят их достоинства и убеждают Вас немедленно применить их на деле. Но
Совместные вычисления
Совместные вычисления Рабочим группам, состоящим из сотрудников одной или нескольких организаций, необходимо взаимодействие и разделение информации. В этой связи многих привлекает клиент-серверное ПО для рабочих групп, обычно называемое групповым ПО (groupware). В основе
2. Способы задания операндов команды
2. Способы задания операндов команды Операнд задается неявно на микропрограммном уровнеВ этом случае команда явно не содержит операндов. Алгоритм выполнения команды использует некоторые объекты по умолчанию (регистры, флаги в eflags и т. д.).Например, команды cli и sti неявно
Порядок вычисления в формулах
Порядок вычисления в формулах Чтобы формула выдавала верный результат, необходимо учитывать порядок вычисления в ней. В этом нет ничего сложного, главное – проявлять внимательность при расстановке знаков в формуле.Для следующего примера создайте таблицу, изображенную
Простейшие вычисления
Простейшие вычисления Вы вручную ввели данные и выровняли колонки, но это можно было сделать и в Word. Теперь следует изучить специфические возможности Excel.В ячейках Excel можно размещать не только числа и текст, но и формулы. В этом случае в ячейке будет виден результат
Операция последовательного вычисления
Операция последовательного вычисления Операция последовательного вычисления последовательно вычисляет два своих операнда, сначала первый, затем второй. Оба операнда являются выражениями. Синтаксис операции:<выражение1>, <выражение2>Знак операции - запятая,
Выражения в качестве операндов
Выражения в качестве операндов Операндом при увеличении или уменьшении значения TIMESTAMP, TIME, DATE или DATE в диалекте 1 может быть константа или выражение. Выражение может быть особенно полезным в ваших приложениях, когда вам надо увеличить или уменьшить значение в секундах,
Контекст вычисления выражений
Контекст вычисления выражений Как мы видели ранее, в XSLT одно и то же правило преобразования может применяться к различным частям XML-документа и в каждом случае результат будет разным — в зависимости от того, как выглядит обрабатываемый фрагмент. Подобно этому,
3.2.2 Порядок вычисления
3.2.2 Порядок вычисления Порядок вычисления подвыражений в выражении неопределен. Напримерint i = 1; v[i] = i++;может вычисляться или как v[1]=1, или как v[2]=1. При отсутствии ограничений на порядок вычисления выражения может генерироваться более хороший код. Было бы замечательно, если
Вычисления, основанные на компонентах
Вычисления, основанные на компонентах В ОО-вычислениях существует только один базовый вычислительный механизм. Есть некоторый объект, всегда являющийся (в силу предыдущего правила) экземпляром некоторого класса, и вычисление состоит в том, что данный объект вызывает
Ингредиенты вычисления
Ингредиенты вычисления При поиске правильной архитектуры ПО критическим является вопрос о модуляризации: какие критерии нужно использовать при выделении модулей наших программ? Чтобы верно ответить на него, нужно сравнить соперничающих кандидатов.
Итоговые вычисления в таблицах
Итоговые вычисления в таблицах В Excel имеются средства для расчета итоговых данных в таблицах и их анализа. Например, с помощью команды Промежуточные итоги можно автоматически разделить таблицу на группы и для каждой из них рассчитать итоговые значения.Мощным
51. Способы задания операндов команды
51. Способы задания операндов команды Операнд задается неявно на микропрограммном уровнеВ этом случае команда явно не содержит операндов. Алгоритм выполнения команды использует некоторые объекты по умолчанию (регистры, флаги в eflags и т. д.).Операнд задается в самой