Rambler's Top100
"Knowledge itself is power"
F.Bacon
Поиск | Карта сайта | Помощь | О проекте | ТТХ  
 Подводные камни
  
О разделе

Список по категориям
Общий список

 
 К н и г и
 
Книжная полка
 
 
Библиотека
 
  
  
 


Поиск
 
Поиск по КС
Поиск в статьях
Яndex© + Google©
Поиск книг

 
  
Тематический каталог
Все манускрипты

 
  
Карта VCL
ОШИБКИ
Сообщения системы

 
Форумы
 
Круглый стол
Новые вопросы

 
  
Базарная площадь
Городская площадь

 
   
С Л С

 
Летопись
 
Королевские Хроники
Рыцарский Зал
Глас народа!

 
  
ТТХ
Конкурсы
Королевская клюква

 
Разделы
 
Hello, World!
Лицей

Квинтана

 
  
Сокровищница
Подземелье Магов
Подводные камни
Свитки

 
  
Школа ОБЕРОНА

 
  
Арсенальная башня
Фолианты
Полигон

 
  
Книга Песка
Дальние земли

 
  
АРХИВЫ

 
 

Сейчас на сайте присутствуют:
 
  
 
Во Флориде и в Королевстве сейчас  14:55[Войти] | [Зарегистрироваться]

ПРОГРАММИСТ.Побочные эффекты при вычислении выражений с функциями

Антон Григорьев
дата публикации 24-07-2002 16:53

КАТЕГОРИЯПРОГРАММИСТ .Побочные эффекты при вычислении выражений с функциями
ПРОДУКТDelphi
ПЛАТФОРМА


function GetZero(Canvas:TCanvas):Integer;
 begin
  Result:=0;
  Canvas.Font.Size:=8
 end;

procedure TForm1.SomeProcedure;
 var a,b:Integer;
  begin
   Canvas.Font.Name:='Times';
   Canvas.Font.Size:=15;
   a:=GetZero(Canvas)+Canvas.TextHeight('A');
   Canvas.Font.Size:=15;
   b:=Canvas.TextHeight('A')+GetZero(Canvas);
   ......
  end;

Итак, функция GetZero возвращает 0, но при этом изменяет размер шрифта. Она его действительно изменяет, это легко проверить. Какие значени должны получить переменные a и b? Для a сначала вызывается GetZero, и кегль шрифта устанавливается в 8, а потом вызывается TextHeight, которая при восьмом кегле и 96 dpi возвращает 17. Для b же всё наоборот - сначала, при кегле 15, вызывается TextHeight, которая вернёт 22, а потом - GetZero. Добавление нуля ничего не меняет, а изменение кегля - тем более, потому что TextHeight уже отработала. На самом деле всё совсем не так. И a, и b получит значение 22, то есть в обоих случаях сначала вызывается TextHeight, и только потом - GetZero. Это видно и из ассемблерного листинга программы. Эффект проявляется и в Delphi 3.0, и в Delphi 4.3, в остальных версиях я не проверял (проверьте, кто сможет). Включение и выключение оптимизации ничего не меняет. Осталось предположить, что в Inprise\Borland очень хорошо знают математику (от перестановки слагаемых сумма не изменяется), но совсем забыли программирование (процесс вычисления первого слагаемого может повлиять на значение второго слагаемого). Чтобы переменная a получила всё-таки нужное значение, приходится идти на хитрость и писать:

a:=GetZero(Canvas);
Inc(a,Canvas.TextHeight('A'));




Комментарий

Компилятор сам выбирает порядок вычисления выражения, в рамках правил данного языка, стремясь построить оптимальный код. Он не может и не должен учитывать зависимость одного слагаемого от другого. Налицо типичный просчет программиста, предположившего выполнение нужного ему побочного эффекта при определенном порядке вычислений операндов выражения.

Подробно о побочных эффектах функций можно почитать в литературе - например, книга Роберта У. Себесты "Основные концепции языков программирования", параграф 6.2.2. Ниже приведены отрывки из этой книги.

... Если ни один из операндов не имеет побочных эффектов, то порядок вычисления несущественен.
... Побочный эффект (side effect) функции, называемый функциональным побочным эффектом (functional side effect), возникает при изменении функцией одного из своих параметров или глобальной переменной.
... Существуют два возможных решения проблемы, связанной с определением порядка вычисления операндов. Во-первых, разработчики языка могут запретить возможность воздействия функции на величину выражения, просто не допуская функционального побочного эффекта. Второй метод борьбы с этой проблемой - указать в определении языка точный порядок вычисления операндов выражений и потребовать от разработчиков средств реализации языка придерживаться именно этого порядка.
... Запретить функциональный побочный эффект трудно, и такой подход уничтожает некоторую гибкость программирования.
... Проблема, связанная с наличием строгого порядка вычислений, состоит в том, что некоторые используемые компиляторами методики оптимизации программ содержат вычисление переупорядоченных операндов. Если же строго задать порядок вычисления, то эти методы оптимизации, выполняемые при вызовах функций, будут не доступны.
... Языки Pascal и Ada позволяют операндам бинарных выражений вычисляться в любом порядке, выбираемом разработчиком средств реализации языка. Более того, функции этих языков могут иметь побочные эффекты, что порождает описанные ранее проблемы.




Смотрите также материалы по темам:
[Видимость переменных] [Процедуры и функции]

 Обсуждение материала [ 24-11-2008 02:54 ] 12 сообщений
  
Время на сайте: GMT минус 5 часов

Если вы заметили орфографическую ошибку на этой странице, просто выделите ошибку мышью и нажмите Ctrl+Enter.
Функция может не работать в некоторых версиях броузеров.

Web hosting for this web site provided by DotNetPark (ASP.NET, SharePoint, MS SQL hosting)  
Software for IIS, Hyper-V, MS SQL. Tools for Windows server administrators. Server migration utilities  

 
© При использовании любых материалов «Королевства Delphi» необходимо указывать источник информации. Перепечатка авторских статей возможна только при согласии всех авторов и администрации сайта.
Все используемые на сайте торговые марки являются собственностью их производителей.

Яндекс цитирования