- •Модульное программирование
- •Технологии программирования
- •Структурное программирование
- •Концепция модульного программирования
- •Процедуры в языке асемблера
- •Организация интерфейса с процедурой
- •Передача аргументов через регистры
- •Передача аргументов через общую область памяти
- •Передача аргументов через стек
- •Использование директив extrn и public
- •Возврат результата из процедуры
- •Связь ассемблера с языками высокого уровня
- •Связь Pascal — асемблер
- •Связь с—асемблер
- •Подведем некоторые итоги:
Структурное программирование
Структурное программирование — методология программирования, базирующаяся на системном подходе к анализу, проектированию и реализации программного обеспечения. Эта методология зародилась в начале 70-х годов и оказалась настолько жизнеспособной, что и до сих пор является основной в большом количестве проектов. Основу этой технологии составляют следующие положения:
Сложная задача разбивается на более мелкие, функционально лучше управляемые задачи. Каждая задача имеет один вход и один выход. В этом случае управляющий поток программы состоит из совокупности элементарных подзадач с ясным функциональным назначением.
Простота управляющих структур, используемых в задаче. Это положение означает, что логически задача должна состоять из минимальной, функционально полной совокупности достаточно простых управляющих структур. В качестве примера такой системы можно привести алгебру логики, в которой каждая функция может быть выражена через функционально полную систему: дизъюнкцию, конъюнкцию и отрицание.
Разработка программы должна вестись поэтапно. На каждом этапе должно решаться ограниченное число четко поставленных задач с ясным пониманием их значения и роли в контексте всей задачи. Если такое понимание не достигается, это говорит о том, что данный этап слишком велик и его нужно разделить на более элементарные шаги.
Понятно, что практическое использование этих положений должно быть подкреплено не только поддержкой со стороны программно-аппаратных средств, но и, в большей степени, личными качествами конкретного программиста, не последними из которых являются наличие опыта проектирования задач и умение подчинить сам процесс программирования некоторой системе.
Конечно, язык ассемблера, в силу его специфики, довольно ограниченно реализует данные положения. В частности, это касается управляющих операторов цикла, условных операторов и операторов выбора. Эти операторы являются встроенными в язык высокого уровня, но в языке ассемблера их попросту нет. Были попытки разработать различные надстройки для языка ассемблера, реализующие эти управляющие операторы, но широкого распространения они не получили. Мне кажется, что это и не нужно, так как реализуемые на языке ассемблера программы решают специфичные системные задачи. Тогда возникает вопрос — а вообще совместимы ли структурное программирование и ассемблер? Ответ положительный, особенно в том случае, если задача поддается разбиению на более мелкие подзадачи. Тогда реализацию этих подзадач можно осуществить с использованием макрокоманд и процедур. Эти механизмы полностью подходят для реализации так называемого модульного программирования, которое является частью структурного подхода. Рассмотрим, что представляет собой модульное программирование.
Концепция модульного программирования
Так же как и для структурной технологии программирования, концепцию модульного программирования можно сформулировать в виде нескольких понятий и положений:
Функциональная декомпозиция задачи — разбиение большой задачи на ряд более мелких, функционально самостоятельных подзадач — модулей. Моду¬ли связаны между собой только по входным и выходным данным.
Модуль — основа концепции модульного программирования. Каждый модуль в функциональной декомпозиции представляет собой «черный ящик» с одним входом и одним выходом. Модульный подход позволяет безболезненно производить модернизацию программы в процессе ее эксплуатации и облегчает ее сопровождение. Дополнительно модульный подход позволяет разрабатывать части программ одного проекта на разных языках программирования, после чего с помощью компоновочных средств объединять их в единый загрузочный модуль.
Реализуемые решения должны быть простыми и ясными. Если назначение модуля непонятно, то это говорит о том, что декомпозиция начальной или промежуточной задачи была проведена недостаточно качественно. В этом случае необходимо еще раз проанализировать задачу и, возможно, провести дополнительное разбиение на подзадачи. При наличии сложных мест в проекте их нужно подробнее документировать с помощью продуманной системы комментариев. Этот процесс нужно продолжать до тех пор, пока вы действительно не добьетесь ясного понимания назначения всех модулей задачи и их оптимального сочетания.
Назначение всех переменных модуля должно быть описано с помощью комментариев по мере их определения.
Исходный текст модуля должен иметь заголовок, в котором отражены как назначение этого модуля, так и все его внешние связи. Этот заголовок можно назвать интерфейсной частью модуля. В этой части с использованием комментариев нужно поместить следующую информацию:
назначение модуля;
особенности функционирования;
описание входных аргументов;
описание выходных аргументов;
использование внешних модулей и переменных;
сведения о разработчике для защиты авторских прав.
В ходе разработки программы следует предусматривать специальные блоки операций, учитывающие реакцию на возможные ошибки в данных или в действиях пользователя. Это очень важный момент, который означает то, что не должно быть тупиковых ветвей в алгоритме программы, в результате работы которых программа «виснет» и перестает отвечать на запросы пользователя. Любые непредусмотренные действия пользователя должны приводить к генерации ошибочной ситуации или к предупреждению о возможности возникновения такой ситуации.
Из этих положений видно, какое большое значение придается организации управляющих и информационных связей между структурными единицами программы (модулями), совместно решающими одну или несколько больших задач.
Применительно к языку ассемблера можно рассматривать несколько форм организации управляющих связей:
Использование механизма макроподстановок, позволяющего изменять исходный текст программы в соответствии с некоторыми предварительно описанными параметризованными объектами. Эти объекты имеют формальные аргументы, что позволяет производить замещение их фактическими аргументами в процессе макрогенерации. Такая форма образования структурных элементов носит некоторый предварительный характер из-за того, что процессы замены происходят на этапе компиляции и есть смысл рассматривать их только как настройку на определенные условия функционирования программы.
Использование механизма подпрограмм, написанных на ассемблере и структурно входящих в одну программу. В языке ассемблера такие подпрограммы называют процедурами. В отличие от макрокоманд, взаимодействие процедур осуществляется на этапе выполнения программы.
Использование механизма подпрограмм, написанных на разных языках программирования и соединяемых в единый модуль на этапе компоновки. Эта возможность реализуется благодаря унифицированному формату объектного модуля, однозначным соглашениям по передаче аргументов и единым схемам организации памяти на этапе выполнения.
Использование механизма динамического (то есть времени выполнения) вызова исполняемых модулей и подключения библиотек dll для операционной системы Windows.
В качестве основных информационных связей можно выделить следующие:
Использование общих областей памяти и общих программно-аппаратных ресурсов микропроцессора для связи модулей.
Унифицированную передачу аргументов при вызове модуля. Эту унифика¬цию можно представлять двояко: на уровне пользователя и на уровне конкретного компилятора.
Унифицированную передачу аргументов при возврате управления из модуля.
Чуть позже мы подробно рассмотрим процессы, происходящие при передаче аргументов. Сейчас в качестве некоторого итога приведенных выше общих рассуждений перечислим средства языка ассемблера по осуществлению функциональной декомпозиции программы:
макросредства;
процедуры;
средства компилятора ассемблера в форме директив организации оперативной памяти и ее сегментации.
Механизм процедур содержит в себе более глубокие вещи, чем тривиальная передача управления из одной точки программы в другую. В частности, он тесно связан со средствами компилятора, поддерживающими организацию памяти и сегментацию. Поэтому дальнейшее обсуждение будет посвящено более глубокому изучению функциональной декомпозиции программ с использованием механизма процедур и связанных с ним средств компилятора.
