Подпрограммы
Мы обсуждали "модули" только как абстрактные объекты. Но любые высокоуровневые языки имеют аппарат, позволяющий кодировать модули проекта как модули реального кода -- отдельные куски, которым можно дать имена и "вызывать" из других кусков кода. Эти куски называются подпрограммами, процедурами или функциями, в зависимости от языка программирования и способа реализации.
Предположим, мы написали "приготовление овсянки" в виде подпрограммы. Это могло бы выглядеть как-нибудь вроде:
процедура приготовление-овсянки взять чистую тарелку открыть коробку с овсянкой насыпать овсянки открыть молоко налить молоко взять ложку конец
Мы можем также написать и "варку-яиц", и "мытье-посуды" в виде подпрограмм. В этом случае можно определить "приготовление-завтрака" как простую программу, которая вызывает эти подпрограммы:
процедура приготовление-завтрака переменная С: булевская (означает спешку) `проверить наличие спешки` если С=истина, то вызвать приготовление-овсянки иначе вызвать варку-яиц конец вызвать мытье-посуды конец
Фраза "вызвать приготовление-овсянки" заставляет выполниться подпрограмму с таким именем. Когда выполнение заканчивается, управление возвращается назад в вызывающую программу в точку, следующую за вызовом. Подпрограммы повинуются законам структурированного программирования.
Как можно видеть, эффект при использовании подпрограмм такой же, как если бы тело этих подпрограмм присутствовало бы в вызывающем модуле. Но, в отличие от кода, производимого макроассемблером, подпрограмма может быть скомпилирована где угодно в памяти, после чего на нее можно просто ссылаться. Не обязательно компилировать ее внутри реального кода главной программы (см. рис. 1-5).
Рис.1-5. Главная программа и подпрограмма в памяти.
Главная программа |-----------------------| ____ |_______________________| / \/ Подпрограмма |_______________________| / +-----------------------+ |_______________________| / | Приготовление-овсянки | | вызвать |/ |_______________________| | приготовление-овсянки | |_______________________| |_______________________|\ |_______________________| |_______________________| \ |_______________________| | | \_____/
Годами ученые-компьютерщики совершенствовались в искусстве использования многочисленных маленьких подпрограмм в сильно разветвленных, протяженных программах. Они могут быть написаны и отлажены независимо друг от друга. Это облегчает повторное использование ранее написанных программ, и так легче распределять части работы между различными программистами. Короткие куски проще продумывать и проверять их правильность.
Когда подпрограммы компилируются в отдельных частях памяти и вызываются ссылками на них, можно использовать одну и ту же подпрограмму много раз без излишнего расходования места на повторы кода подпрограммы. Так разумное использование подпрограмм может уменьшать размеры кода.
К сожалению, при этом имеется проигрыш в скорости исполнения. Проблему создает необходимость сохранения содержимого регистров перед переходом на подпрограмму и их восстановления при возвращении оттуда. Еще больше времени требуют невидимые, но существенные участки кода, необходимые для передачи параметров в и из подпрограммы.
Существенен также сам способ вызова и передачи параметров подпрограмме. Для автономного тестирования подпрограммы приходится писать специальные тестовые программы для ее вызова.
По этой причине ученые рекомендуют умеренное использование подпрограмм. На практике они обычно получаются довольно большими, от половины до целой страницы текста в длину.