Предыдущий раздел ОСНОВНЫЕ ОПЕРАТОРЫ АССЕМБЛЕРА Следующая глава

1.8. Макрооператоры

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

   <имя макрооператора>  [список фактических параметров]

  Пример макрооператора:

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), то вклад этих команд в продолжительность выполнения тем больше, чем меньше подпрограмма. С другой стороны, чем длиннее тело макроопределения, тем больше затраты памяти на его “тиражирование”. Следовательно, короткие повторяющиеся последовательности операторов лучше оформлять в виде макроопределений, а длинные – в виде подпрограмм.

 


Предыдущий раздел В начало Следующая глава