TURBO PASCAL

Новости

Программы   

Turbo Pascal 

Игры

Документация   

Странности

FAQ

Ссылки

Форум

Гостевая книга

Рассылка

Благодарности

Об авторе

 

 

Структурирование программ,

как структурировать программы, что такое локальные переменные, чем различаются параметры, и, наконец, как писать библиотеки.

 

Процедуры и функции,

или эффективная структуризация программ

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

Необходимо сразу отметить, что В предыдущем уроке были указаны два ключевых свойства процедур
процедура делает нечто неочевидное, и
процедура имеет параметры - входные и выходные.

 

Из этих двух свойств напрямую вытекает обоснованный принцип выделения участков алгоритма в процедуры:
если некоторый участок алгоритма обрабатывает некоторый определенный набор данных (1) и/или производит определенные действия в зависимости от них же, генерируя при этом некоторые новые значения некоторых (возможно, что тех же) данных, то он (участок) должен быть выделен в процедуру. Если при этом генерируется одно значение, то процедура заменяется функцией.
Соответственно, обрабатываемые данные являются входными параметрами, а генерируемые - выходными (или значением функции).

Другой, не менее справедливый принцип выделения участков кода в процедуры и функции приводит Рубенкинг: "если программа делает что-либо не менне трех раз, следует создать процедуру"

И последнее: если выделение участка кода в процедуру (функцию) сделает программу более читабельной и понятной, следует это сделать.

Существует различие между входными и выходными параметрами: первые должны только передаваться в процедуру (функцию) а вторые - передаваться и возвращаться из нее. Pascal поддерживает оба типа параметров.

Все нижесказанное о процедурах относится в равной степени и к функиям, если особо не оговорено обратное.

Стоит отметить, что при выделении некоторого участка кода в процедуру следует определить степень универсальности (как можно большую) данной процедуры и уже в зависимости от нее определять количество параметров. Кроме того, не стоит перегружать процедуру большим набором функциональных возможностей. Так, в частности, процедура, ход (алгоритм) выполнения которой существенно зависит от более чем трех параметров, почти наверняка может быть разбита на две, а то и три отдельных (хотя и взаимосвязанных) процедуры.

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

 

Локальные переменыне,

или что мое - то МОЕ

Как ясно из синтаксиса, внутри процедуры можно объявлять переменные, типы и константы (а впрочем и процедуры), называемые локальными, в отличие от глобальных, объявляемых в соответствующих частях основной программы.

Локальные переменные отличаются от глобальных сроком существования и месторасположением:
глобальные переменные размещаются в сегменте данных в процессе загрузки программы в оперативную память и удаляются в процессе выгрузки программы. Соответственно они доступны всегда и из любого места программы;
локальные переменные создаются при вызове процедуры в стеке (создается так называемый стековый фрейм, для реального режима i80x86 - к SP прибавляется суммарный объем локальных переменных с учетом выравнивания) и удаляются при возврате, а адресуются при этом смещением от вершины стека. Вследствие этого они (переменные) доступны ровно тогда, когда стек остается неизменным, иными словами только внутри тела процедуры.

 

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

Процедуры и функции: передача параметров,

или ссылки и значения

Слово "параметр" в программировании может употребляться по отношению к двум типам объектов:
к переменным и значениям выражений передаваемым в процедуры;
к переменным принимаемым процедурами.

 

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

Параметры в процедуры и функции передаются через стек (то есть в стеке создаются копии фактических параметров или их адреса - именно с этими копиями связаны формальные параметры). При этом они делятся на две категории, отличающиеся способом передачи:
параметры, передаваемые по значению (невозвращаемые, неизменяемые, параметры-значения);
парметры, передаваемые по ссылке (возвращаемые, изменяемые, параметры-переменные).

 

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

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

Более подробно о различиях механизмов передачи и возврата параметров автор настойчиво рекомендует посмотреть здесь.

Естественно, что для передачи входных параметров процедуры используют, за нижеописанным исключением, параметры, передаваемые по значению, а выходных - передаваемые по ссылке. Здесь стоит отметить, что параметр, переданный по значению займет в стеке ровно столько места, сколько определяется его типом, а передаваемый по ссылке - всегда четыре байта (точнее - размер указателя). С другой стороны, прямое обращение к параметру-значению производится быстрее косвенного обращения к параметру переменной.

Вследствие этого, параметры размер которых угрожает стеку переполнением (по различным причинам) следует передавать по ссылке.

Модульное программирование,

или сделаем из кладовки библиотеку

Кодирование ряда (однотипных) задач может потребовать использования похожих (или одних и тех же) процедур в различных программах. Для того, чтобы не переписывать такого рода процедуры каждый раз заново, большинство программистов хранят (а иногда и собирают) исходные коды различных программ с целью многократного повторного использования.

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

Именно такое состояние - кладовка процедур (с присущим кладовке бардаком) существовала до тех пор, пока умным программистам не пришла в голову идея объединить процедуры со связанными с ними переменными и типами и предоставить все это вместе программисту в виде библиотеки. Концепция же получила название модульного программирования.

Рассмотрим как библиотеки, или модули, оформляются на Pascal'е, а затем поговорим о применении данной концепции.

Модуль представляется в виде текстового файла с особой структурой:

Unit <имя модуля>; {имя модуля}
Interface {начало интерфейсной части}
[Uses-часть]
[Var-часть]
[Const-часть]
[Type-часть]
[Часть объявления (декларации) процедур]
Implementation {начало части реализации} [Uses-часть]
[Var-часть]
[Const-часть]
[Type-часть]
[Определение (дефиниция) процедур из Interface] [Определение внутренних процедур]
[Begin часть инициализации]
End.

В квадратные скобки заключены части, наличие которых не обязательно. Правила оформления Var-, Type-, и Const- частей такие же, как и в обычных программах, в частности их может быть много.

В интерфейсной части описываются типы, константы и переменные, и заголовки (декларации) процедур, предоставляемые автором модуля программисту его использующему. В части реализации каждая из деклараций части интерфейса повторяется с определением тела процедуры (производится дефиниция). Кроме того определяются внутренние (не предоставляемые для внешнего использования) типы, процедуры, константы и переменные.

(Необязательная) часть инициализации модуля выполняется до выполнения первого оператора программы, данный модуль использующей.

Поговорим о том, какие процедуры и типы следует объединять в один и тот же модуль. Насколько известно автору существует два принципа объединения процедур в модуле:
функциональный, согласно которому в один модуль объединяются процедуры, выполняющие связанные по смыслу действия, к примеру вывод и обработку окон, обработку строк, работу со связными списками, etc.;
по уровню реализации, когда в один модуль объединяются процедуры работающие с некоторыми объектами (как правило аппаратно-зависимыми) на определенном уровне - физическом или логическом. Примеры - библиотеки работы с диском на уровне портов на уровне прямого доступа и на уровне файловой системы; модули работы с экраном, etc.

 

(1) (обратно) Под данными можно понимать все что угодно - от переменных до событий и ввода пользователя.

 

На первую страницу

Rambler's Top100 Rambler's Top100
PROext: Top 1000

(с)Все права защищены

По всем интересующим вопросам прошу писать на электронный адрес

Hosted by uCoz