Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Учебное пособие 3000239.doc
Скачиваний:
23
Добавлен:
30.04.2022
Размер:
1.12 Mб
Скачать

7.5. Локальные данные процедур

Во многих процедурах не возникает проблемы с хранением локальных данных (величин, нужных только на время выполнения процедуры) – для них достаточно и регистров. Однако если в процедуре много локальных данных, тогда возникает вопрос: где отводить место для них? Конечно, можно выделить место в сегменте данных, но это плохо, т. к. большую часть времени это место памяти будет пропадать зря. Лучше выделять это место в стеке: при входе в процедуру в вершине стека «захватывается» нужное число байтов для локальных данных, а перед выходом это место освобождается. В таком случае место в памяти занимается только на время выполнения процедуры.

Такой «захват» места в стеке можно делать как в случае передачи параметров процедуре через регистры, так и в случае передачи параметров через стек. Для этого надо запомнить в стеке текущее значение регистра ВР и затем установить его на вершину стека (при передаче параметров через стек это есть ничто иное, как «входные» действия), после чего надо уменьшить значение указателя стека SP на число «захватываемых» байтов. Например, если некоторой процедуре Р требуется 3 байта (скажем, 2 байта под локальную переменную А и 1 байт под локальную переменную В), тогда указанные действия реализуются следующими командами (на рис. 39 изображено состояние стека после этих команд):

P PROC

PUSH BP

MOV BP,SP

SUB SP,3

...

Рис. 39. Хранение локальных данных в стеке

После этого доступ к локальным данным осуществляется с помощью выражений вида [ВР-k]; например, [ВР-2] - это адрес локальной переменной А, а [ВР-3] - адрес локальной переменной В.

При завершении работы процедуры надо выполнить такие действия:

...

MOV SP, BP ;отказ от места для локальных данных

POP BP ;восстановление старого значения ВР

RET ;(или RET n) - возврат из процедуры

Р ENDS

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

Воспользуемся следующим алгоритмом. Заводим в стеке локальный массив из 256 байтов – по одному на каждый возможный символ, причем символу с кодом к поставим в соответствие байт стека с адресом [BP-256+k], т. е. нумеруем элементы этого стекового массива «сверху вниз», и обнуляем этот массив. Затем просматриваем заданную строку и для каждого входящего в нее символа записываем 1 в соответствующий элемент локального массива; тем самым в этом массиве будут отмечены все символы, которые хотя бы раз входили в строку. В конце подсчитываем число единиц в локальном массиве.

DIF PROC

; «входные» действия

PUSH BP

MOV BP, SP

SUB SP, 256

;занять место в стеке под локальный массив

PUSH ВХ

;спасти регистры, используемые в процедуре

PUSH СХ

PUSH SI

;обнуление локального массива

MOV АХ, СХ ;сохранить длину строки

MOV СХ, 256 ;длина локального массива

MOV SI, 0 ;индекс в этом массиве (от 0 до 255)

DIF1: MOV BYTE PTR [BP-256+SI], 0

INC SI

LOOP DIF1

MOV СХ, АХ ;восстановить в СХ длину строки

;просмотр строки и запись 1 в локальный массив

MOV АН, 0 ;для расширения AL —> АХ

DIF2: MOV AL,[ВХ] ;код очередного символа строки

MOV SI,AX ;перепись его в модификатор SI

MOV BYTE PTR [BP-256+SI], l

;запись 1 в локальный массив

INC BX ; адрес следующего символа

LOOP DIF2

;подсчет числа 1 в локальном массиве

MOV АХ, 0 ; счетчик единиц

MOV СХ, 256 ; длина локального массива

MOV SI, 0 ; индекс в этом массиве

DIF3: CMP BYTE PTR [BP-256+SI], 1

JNE DIF4

INC AX

DIF4: INC SI

LOOP DIF3

; «выходные» действия

POP SI ; восстановить регистры

POP СХ

POP BX

MOV SP, BP ;освободить стек от лок. массива

POP ВР ;восстановить старое значение ВР

RET

DIF ENDP