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

4.3. Команды управления циклом

С помощью команд перехода можно реализовать любые разветвления и циклы. Например, следующие операторы языка Паскаль

а)if X>0 then S1 else S2

б)while X>0 do S

в)repeat S until X>0

где S, S1 и S2 - какие-то операторы, а X - знаковая переменная, реализуются по таким схемам (рис. 26).

Рис. 26. Реализация ветвлений и циклов

Среди циклов на практике наиболее часто встречаются циклы с заранее известным числом повторений (for-циклы языка Паскаль), поэтому в систему команд многих ЭВМ обычно включают дополнительные команды, упрощающие реализацию подобных циклов и называемые командами управления циклом.

Команда LOOP

Пусть некоторую группу команд (тело цикла) надо повторить N раз (N>0). Тогда на языке ассемблера этот цикл можно реализовать по такой схеме:

MOV CX, N ;CX-счетчик цикла(число повторений)

L: ... ;

... ; тело цикла

... ;

DEC CX ;СХ:=СХ-1

СМР СХ, 0 ;СХ=07

JNE L ;СХ<>0 -> goto L

Как видно, в конце таких циклов всегда применяется одна и та же тройка команд. Учитывая это, в систему команд ПК была введена специальная команда, которая объединяет в себе действия этих трех команд:

Управление циклом по счетчику: LOOP <метка>

Действие этой команды можно описать так:

СХ:=СХ-1; if CX<>0 then goto <метка>

С помощью команды LOOP наш цикл запишется следующим образом:

MOV CX, N ;N>0

L: ... ;

... ; тело цикла

... ;

LOOP L

Как видно, получилось короче, да и работает команда LOOP быстрее эти трех команд. Поэтому, если можно, следует пользоваться командой LOOP.

Однако необходимо учитывать ряд особенностей этой команды.

Во-первых, команда LOOP требует, чтобы в качестве счетчика цикла обязательно использовался регистр СХ, при другом регистре команду применять нельзя.

Во-вторых, начальное значение для СХ должно быть присвоено до цикла, причем этому регистру надо присваивать ровно столько, сколько раз должен повторяться цикл – без всяких «плюс-минус единица». Например, если цикл должен выполняться 100 раз, то в регистр СХ надо записывать именно 100, а не 99 или 101.

В-третьих, поскольку команда LOOP ставится в конце цикла, тело цикла хотя бы раз обязательно выполнится. Поэтому для случая СХ=0 наша схема цикла не подходит. Так вот, если возможен вариант, что число повторений может быть и нулевым, то при СХ=0 надо сделать обход цикла:

MOV CX, N ; N>=0

JCXZ L1 ; CX=0 -> L1

L: ... ;

... ; тело цикла

... ;

LOOP L

L1: ...

Именно ради осуществления таких обходов в ПК и была введена команда условного перехода JCXZ. В иных ситуациях она используется редко.

В-четвертых, как и команды условного перехода, команда LOOP реализует только короткий переход, поэтому расстояние от нее до начала цикла (метки L) не должно превышать 127-128 байтов (примерно 30-40 команд). Если цикл содержит больше команд, тогда команду LOOP использовать нельзя и надо реализовывать цикл по-иному.

Рассмотрим конкретный пример на использование команды LOOP. Пусть N -байтовая переменная со значением от 0 до 8 и надо в регистр АХ записать фак­ториал этого числа: AX:=N! (отметим, что 8! = 40320 < ).

Для решения этой задачи надо вначале положить АХ:=1, а затем N раз выполнить умножение AX:=AX*i, меняя i от 1 до 8. При этом следует учитывать, что при N=0 цикл не должен выполняться.

MOV АХ, 1 ;АХ:=0!

MOV CL, N

MOV CH, 0 ;CX:=N как слово (счетчик цикла)

JCXZ F1 ;при N=0 обойти цикл

MOV SI, 1 ;i:=1

F: MUL SI ;(DX,AX):=AX*i (DX=0)

INC SI ;i:=i+l

LOOP F

F1:

Отметим, что в данном примере параметр цикла (i) можно было бы менять и в «обратном» направлении - от N до 1, а поскольку именно так меняется и регистр СХ, то этот регистр можно использовать не только как счетчик цикла, но и как параметр цикла (CX=i):

MOV АХ, 1

MOV CL, N

MOV CH,0 ;CX-и счетчик цикла, и параметр цикла

JCXZ F1

F: MUL CX

LOOP F

F1:

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

Команды LOOPE/LOOPZ u LOOPNE/LOOPNZ

Эти команды похожи на команду LOOP, т. е. заставляют цикл повториться столько раз, сколько указано в регистре СХ, однако они допускают и досрочный выход из цикла.

Цикл по счетчику и пока равно (пока ноль): LOOPE <метка> или LOOPZ <метка>

(Названия LOOPE и LOOPZ являются синонимами.) Действие этой команды можно описать так:

CX:=CX-1; if(CX<>0) and (ZF=1) then goto <метка>

Таким образом, эта команда совмещает в себе изменение счетчика цикла (регистра СХ) и условный переход, когда счетчик еще не нулевой и когда предыдущая команда выработала флаг нуля, равный 1. Причем этот переход - короткий.

Команда LOOPE используется для организации цикла с известным числом повторений, из которого возможен досрочный выход. До начала цикла в регистр СХ записывается число повторений. Сама команда LOOPE ставится в конец цикла (ее операнд - метка первой команды цикла), а перед ней помещается команда, меняющая флаг ZF (обычно это команда сравнения СМР). Команда LOOPE заставляет цикл повторяться СХ раз, но только если предыдущая команда фиксирует равенство сравниваемых величин (вырабатывает нулевой результат).

По какой именно причине произошел выход из цикла (по ZF=0 или СХ=0), надо проверять после цикла. Причем надо проверять флаг ZF (по команде JE/JZ или JNE/JNZ), а не регистр СХ, т. к. условие ZF=0 («не равно») может появиться как раз на последнем шаге цикла, когда и регистр СХ стал нулевым.

Чаще всего команда LOOPE используется для поиска первого элемента некоторой последовательности, отличного от заданной величины. Пусть, к примеру, надо записать в регистр BL наименьшее число из отрезка [2, К], на которое не делится число N (К и N - байтовые переменные, 2<=K<N), или записать 0, если такого числа нет. Для этого будем последовательно делить N на числа 2, 3, …, К и сравнивать остатки от деления с 0 – до тех пор, пока не найдется ненулевой остаток либо не будет исчерпаны все числа отрезка:

MOV DL, N

MOV DH, 0 ;DX:=N как слово

MOV CL, K

MOV CH, 0

DEC CX ;CX:= K-1 (счетчик цикла)

MOV BL, 1

DV: INC BL ;очередное число из [2,K]

MOV AX, DX

DIV BL ;AH:=N mod BL

CMP AH, 0 ;mod=0?

LOOPE DV ;цикл СХ раз и пока mod=0

JNE DV1 ;mod<>0 --> DV1

MOV BL, 0 ;нет искомого числа

DV1:

Еще одна команда ПК для организации циклов:

Цикл по счетчику и пока не равно (пока не ноль):

LOOPNE <метка> или LOOPNZ <метка>

(Название LOOPNE и LOOPNZ являются синонимами.)

Эта команда аналогична команде LOOPE/LOOPZ, но выход из цикла осуществляет при CX=0 или ZF=1 (если предыдущая команда зафиксировала равенство, дала нулевой результат). Ее действие:

CX:=CX-1; if (CX<>0) and (ZF=0) then goto <метка>

Команда LOOPNE обычно используется для поиска в некоторой последовательности первого элемента, имеющего заданную величину.