Предыдущий раздел | ОСНОВНЫЕ ОПЕРАТОРЫ АССЕМБЛЕРА | Следующая глава |
Макрооператор – оператор, заменяющий в программе на ассемблере последовательность обычных операторов (исполнительных операторов и псевдооператоров). То есть вместо того, чтобы записывать в программе несколько операторов, мы помещаем в нее единственный макрооператор. Структура макрооператора:
<имя макрооператора> [список фактических параметров]
Пример макрооператора:
Out_str Buff
Здесь макрооператор Out_str предназначен для вывода на экран строки символов, расположенной в области памяти с именем Buff.
В начале своей работы транслятор-ассемблер выполняет для каждого макрооператора макрорасширение – заменяет макрооператор на соответствующую совокупность операторов ассемблера. После завершения макрорасширений текст программы не содержит макрооператоров и представляет собой обычную ассемблерную программу.
Для того, чтобы транслятор мог выполнить макрорасширение, имя макрооператора должно быть определено в макроопределении. Структура макроопределения:
%macro <имя макрооператора> [количество формальных параметров]
. . . . . . . . . . . . . . . ; Тело макроопределения
%endmacro
Пример макроопределения:
%macro Out_str 1
;
; Вывод строки на экран
; ----------------------------------
; Вход: %1 – адрес-смещение выводимой строки
;
push ax
push dx
mov ah, O9h
mov dx, %1
int 21h
pop dx
pop ax
%endmacro
При выполнении макрорасширения для Out_str транслятор заменит этот макрооператор на тело макроопределения, причем он заменит формальный параметр Str в теле макроопределения на фактический параметр Buff. (В примере такая замена выполняется в единственном операторе mov.)
Где расположить макроопределение? Здесь можно использовать два варианта. В первом из них макроопределение располагается в начале того же файла, где оно будет использоваться. Недостаток: в каждом файле, где предполагается использовать аналогичный макрооператор, его придется описывать заново. Во втором варианте макроопределение выносится в отдельный файл (текстовый ASCII-файл, полученный с помощью любого текстового редактора). А в начале каждого ассемблерного файла, где предполагается использовать макроопределение, записывается псевдооператор %include с указанием имени включаемого файла. Например:
%include ”Outstr.inc”
Обычно в один включаемый файл помещают несколько макроопределений и, возможно, описания структур (которые фактически являются разновидностью макроопределений). При выполнении транслятором псевдооператора %include весь включаемый файл подсоединяется к тексту программы, содержащей %include, но на текст машинной программы наличие этого файла не влияет.
Полезно выполнить сравнение макроопределений с подпрограммами. Оба эти типа модулей позволяют программисту инициировать выполнение многих операторов с помощью единственного оператора (call или int для подпрограммы и макрооператор для макроопределения). Но механизм их реализации совершенно различен. В то время как тело макроопределения будет записано транслятором всюду, где он встретит соответствующий макрооператор, тело подпрограммы находится в памяти в единственном экземпляре, а операторы call (или int) выполняют передачу управления этому экземпляру. Отсюда можно сделать более обоснованным выбор между этими типами модулей.
Так как каждое выполнение подпрограммы связано с “накладными расходами” в виде двух машинных команд (call и ret, или int и iret), то вклад этих команд в продолжительность выполнения тем больше, чем меньше подпрограмма. С другой стороны, чем длиннее тело макроопределения, тем больше затраты памяти на его “тиражирование”. Следовательно, короткие повторяющиеся последовательности операторов лучше оформлять в виде макроопределений, а длинные – в виде подпрограмм.
Предыдущий раздел | В начало | Следующая глава |