Форум программистов, компьютерный форум, киберфорум
Assembler, MASM, TASM
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск  
 
 
Рейтинг 4.63/2256: Рейтинг темы: голосов - 2256, средняя оценка - 4.63
Ушел с форума
Автор FAQ
 Аватар для Mikl___
16374 / 7686 / 1080
Регистрация: 11.11.2010
Сообщений: 13,762
15.11.2013, 04:52  [ТС]
ГЛАВА 13
ПЕРЕХОДЫ И ЦИКЛЫ
(часть 4/5)

Команды управления циклом
С помощью условных операторов и логических и арифметических команд теоретически можно организовать сколь угодно сложный алгоритм. Однако на практике при необходимости можно организовать обработку тысяч элементов массива (например, присвоить каждому элементу начальное значение), вручную набирать тысячу операторов присваивания крайне тяжело.
Поэтому в языках программирования имеются средства для организации повторных вычислений, называемые операторами цикла. С помощью команд перехода на языке ассемблера можно реализовать любые разветвления и циклы. Например, за следующими операторами на языках Паскаль, BASIC и Си.
Рис. 13.3.1
Рисунок |Паскаль| BASIC |Си, Си++
(a)|
if X>0 then S1
else S2;|IF X>0 THEN S1
ELSE S2
ENDIF|
if (X>0) S1
else S2;
(b) |while X>0 do S;| DO WHILE X>0 S
LOOP
|while (X>0) S;
(c) |repeat S until X<0|| do S until (X<0);
Где S, S1 и S2 какие-то операторы, а X – знаковая переменная, скрываются следующие ассемблерные команды
 CMP X,0 BEG: CMP X,0 BEG: S
 JLE L2 JLE FIN CMP X,0
 S1 S JG BEG
 JMP FIN JMP BEG  
L2: S2 FIN:   
FIN:     
 (a) (b) (c)
Если Вам необходимо по каким-то причинам скрыть условный переход, то помните, что конструкция b*x + NOT(b)*y эквивалентна условному выражению if (b==TRUE) then x else y. Вместо умножения и сложения можно использовать логическое умножение (AND) и сложение (OR).
Циклы
Допустим в вашей программе необходимо решить уравнение (A+B)*C=D. Хорошо, если известно, что A=1, B=5, C=7. Посчитать D – нет никаких проблем. А если эти числа получаются после других восьмиэтажных уравнений? Подойдем к решению задачи творчески (для простоты считаем что размерность A, B и C – байт):
Assembler
1
2
3
4
mov al,A
add al,B ;al=A+B
mul C ;ax=(A+B)*C
mov D,ax ;D=(A+B)*C
Допустим, надо пересчитать этот фрагмент 10 раз с разными значениями A, B и C. Как? Десять раз переписать? Нет – нам нужно каким-то образом заставить компьютер выполнять повторяющиеся вычисления. Вообще говоря, именно эта потребность является одной из главных причин использования машин для выполнения арифметических вычислений. Цикл – это набор операций, который регулярно повторяется в одной и той же последовательности.
Существует три основных типа цикла: циклы с условием в начале, циклы с условием в конце и циклы с условием в середине. Кроме того, существуют комбинированные циклы, которые имеют несколько условий в разных местах, например в начале и конце одновременно. Циклы с условием в начале – это циклы с предусловием, while-циклы. Цикл с условием в конце – это цикл с пост-условием, do /while или repeat / until – циклы. Блок статического предсказания направлений ветвлений процессоров Pentium оптимизирован под переходы, направленные в область младших адресов (назад). Поэтому циклы с постусловием должны выполняться быстрее циклов с предусловием. Циклы со счетчиком представляют собой синтаксическую разновидность циклов с предусловием. Замена цикла с приращением на цикл с убыванием счетчика делает ненужной команду CMP. Цикл с условием в середине называется break-циклы.
Существует целых два основных варианта оператора повторения, причем каждый для своих целей:
1) повторение, управляемое вычисляемым условием, и
2) повторение, управляемое явным счетчиком или списком значений.
В первую группу входят два оператора:
while b do S
и
repeat S until not b
Среди циклов на практике часто встречаются циклы с заранее известным числом повторений (for-циклы), поэтому в систему команд многих ЭВМ обычно включают дополнительные команды, упрощающие реализацию подобных циклов.
Команда LOOP (LOOPW, LOOPD)
Синтаксис команды:
LOOP <TARGET>
Пусть некоторую группу команд (тело цикла) надо повторить N раз (N>0). Когда-то на языке ассемблера этот цикл реализовали по такой схеме:
Assembler
1
2
3
4
5
MOV CX,N ;CX – счетчик цикла
LOOP: . . . ;тело цикла
DEC CX ;CX-1->CX
CMP CX,0 ;CX=0?
JNE LOOP ;если CX не равен 0 идти к метке LOOP
Создатели языка ассемблера обратили внимание, что в конце таких циклов всегда применяется одна и та же тройка команд (dec cx/cmp cx,0/jne loop). Учитывая это, в систему команд была введена специальная команда LOOP («петля»), которая объединяет в себе действие всех этих команд.
Действие команды LOOP немного сходно с циклом FOR-NEXT в Бейсике или соответствует паре инструкций REAPET-UNTIL, где инструкция REAPET означает начало блока инструкций цикла. Как и для цикла FORNEXT в Бэйсике, мы должны сообщить LOOP о том, сколько раз запускать цикл. Мы делаем это, помещая счетчик повторений в регистр RCX/ECX/CX. В каждом цикле микропроцессор вычитает единицу из RCX/ECX/CX, и когда RCX/ECX/CX становится равным нулю, LOOP заканчивает цикл. С помощью команды LOOP наш цикл запишется следующим образом:
Assembler
1
2
3
4
5
6
7
8
9
 mov cx,N;cx – счетчик цикла
;-- тело цикла-------------
L: mov al,A
add al,B;al=A+B
mul C;ax=(A+B)*C
mov D,ax;D=(A+B)*C
. . .
;----------------------------
LOOP L
Получилось короче, и работает команда LOOP быстрее трех команд.
Необходимо учитывать ряд особенностей команды LOOP:
  1. команда LOOP требует, чтобы в качестве счетчика цикла обязательно использовался регистр CX/ECX;
  2. начальное значение регистру CX/ECX должно быть присвоено до начала цикла;
  3. так как команда LOOP ставится в конце цикла, тело цикла хотя бы раз должно выполниться;
  4. если по какой-либо причине перед началом цикла регистр CX/ECX равен 0, то тело цикла все равно будет выполнено, из содержимого регистра CX/ECX будет отнята 1 и уже после этого регистр CX/ECX будет проверен на равенство 0. Что, по вашему, окажется в регистре CX/ECX? Правильно, содержимое регистра CX/ECX равно –1 (0FFFFh/0FFFFFFFFh) и цикл, вместо того чтобы остановиться, будет запущен еще 65535 раз, если мы используем регистр CX, или 4 миллиона раз (!), если использовали регистр ECX, – это один из источников ошибок.
    Поэтому, если возможен вариант, что число повторений может быть и нулевым, то при CX /ECX =0 надо делать обход цикла:
    Assembler
    1
    2
    3
    4
    5
    
    MOV ECX,N ;N>=0
    JECXZ L1 ;если ECX=0 перейти на L1
    L:;
    LOOP L
    L1: . . .
    Именно ради осуществления таких обходов и были введены команды условного перехода JCXZ/JECXZ;
  5. команда LOOP реализует только короткий переход, поэтому расстояние от LOOP до начала цикла не должно превышать 127 байтов вниз или 128 байтов вверх.
Процедуры возвращают какое-либо значение в регистре EAX, которые на равенство/неравенство нулю проверяют последовательностью команд:
Команда Код Длина (байт)
Самый неоптимальный вариант
cmp eax,0 83F800 или 3D00000000 3 байта или 5 байтов
jz TARGET 74XX или 0F84XXXXXXXX 2 короткий или 6 длинный
Итого: от 5 до 11 байт
Более короткий вариант – TEST ничего не пишет в регистр (OR и AND пишут),
поэтому эта инструкция лучше спаривается, значит и код будет более быстрым
test eax,eax/85C0 или2 байта
and eax,eax/23C0 или 
or eax,eax0BC0 
jz TARGET 74XX или 0F84XXXXXXXX 2 или 6 байтов
Итого: от 4 до 8 байт
Самый короткий вариант – Если вам не важно содержимое регистра ECX
или неважно, где будет находится содержимое EAX
xchg eax,ecx 91 1 байт
jecxz TARGET E3XX 2 байта
Итого: 3 байта
Иногда по смыслу требуется команда jecxnz TARGET, которую можно сэмулировать последовательностью inc ecx/loop TARGET команда inc ecx необходима потому, что loop вычтет 1 из содержимого ecx и если там окажется 0, перехода к TARGET не произойдет.
Если вам необходим бесконечный цикл – воспользуйтесь командой JMP, а если не знаете сколько раз придется запускать цикл, используйте команды условного перехода.
Если программа транслируется в 32-разрядном режиме, команда LOOP автоматически использует регистр ECX в качестве счетчика циклов.
Команда LOOPW использует регистр CX в качестве счетчика циклов в 32-разрядном режиме. Фактически это та же самая LOOP, предваряемая префиксом 67h. Если программа транслируется в 16-разрядном режиме, команда LOOPD использует регистр ECX в качестве счетчика циклов. Фактически это та же LOOP, предваряемая префиксом 67h.
Команды LOOPE/LOOPZ и LOOPNE/LOOPNZ
(Цикл по счетчику пока равно/ = “LOOP if Equal”
Цикл по счетчику пока ноль = “LOOP if Zero”
Цикл по счетчику пока не равно = “LOOP if Not Equal”
Цикл по счетчику пока не ноль = “LOOP if Not Zero”)
Синтаксис команд:
LOOPE <TARGET>
LOOPZ <TARGET>
LOOPNE <TARGET>
LOONZ <TARGET>
Эти команды похожи на команду LOOP, то есть заставляют цикл повториться столько раз, сколько указано в регистре CX/ECX, однако они допускают и досрочный выход из цикла.
Команда LOOPE используется для организации цикла с известным числом повторений, из которого возможен досрочный выход. До начала цикла в регистр CX/ECX записывается число повторений. Команда LOOPE ставится в конец цикла, а перед ней помещается команда, меняющая флаг ZF – обычно это команда сравнения CMP. Команда LOOPE заставляет цикл повторяться CX/ECX раз, но только если команда CMP фиксирует неравенство сравниваемых величин – происходит выход из цикла. По какой именно причине произошел выход из цикла (по ZF=0 или CX/ECX=0), надо проверять после цикла. Чаще всего команда LOOPE используется для поиска первого элемента некоторой последовательности, отличного от заданной величины. Команда LOOPZ – синоним команды LOOPE.
Команда LOOPNE аналогична команде LOOPE, но выход из цикла осуществляется при ZF=1, если предыдущая команде LOOPNE команда CMP зафиксировала равенство или по CX/ECX=0. Команда LOOPNE обычно используется для поиска в некоторой последовательности первого элемента, имеющего заданную величину. Команда LOOPNZ – синоним команды LOOPNE.
Пусть ASCII_STR является переменной, ассоциируемой с началом цепочки из L символов, и в цепочке необходимо найти символ пробела. Цикл заканчивается, когда обнаружен пробел или когда просмотрена вся цепочка. Если пробел не найден, осуществляется переход к метке NOT_FOUND:
Assembler
1
2
3
4
5
6
 MOV ECX,L ;передать размер массива в ECX
MOV EDI,offset ASCII_STR ;инициализировать индекс
MOV AL,’ ’ ;загрузить в AL код пробела
NEXT: SCASB ;проверить на символ пробела
LOOPNE NEXT ; зациклить, если не пробел и ECX не равен 0
JNZ NOT_FOUND ; перейти к NOT_FOUND,если пробел не найден
0
Закрытая тема Создать тему
Новые блоги и статьи
Вот представьте что вам дали бессмертие.
kumehtar 24.07.2026
Вот представьте что вам дали бессмертие, ничего более не меняя. Вообще ничего, только бессмертие в нынешнем виде. Рады были бы? Что бы вы тут делали всё это время? Никакой пенсии. Никакого нового. . .
сукцессия 41
anaschu 24.07.2026
Численная верификация бифуркации в агентной модели лесной сукцессии: от одного параметра к ансамблю Автор: пользователь @Shumilov_AS | Раздел: Прикладная математика / Численные методы Кратко. . .
сукцессия 40. Ансамблевая кластерная параметризаци, часть 1.
anaschu 24.07.2026
Пр# Сопровождение научной статьи ИИ-ассистентом: подготовка публикации и калибровка агентно-ориентированной модели сукцессии микоризных систем **Полевые заметки о двухнедельной совместной работе**. . .
Теория всего 12. ВГК на планете в стратегической игре "терра"
anaschu 21.07.2026
### Главные семантические изменения и дешифровка новой физики 1. **`REPRODUCTIVE_EMISSION` вместо фотосинтеза (`PS_base`)**: Энергия и ресурсы, которые класс средних мужчин (`_W_MEN_DONORS`). . .
Публикация отклонённая на хабре. Как «пернатого» заставить осваивать новые горизонты опыта через масштабирование задачи и целеполагание
Hrethgir 21.07.2026
https:/ / www. cyberforum. ru/ blog_attachment. php?attachmentid=11948&stc=1&d=1784657928 Привет Хабр. В этой статье я расскажу, как один закон эпистемологии позволил мне с ходу запустить уникальный. . .
Теория всего 11. Основные параметры
anaschu 21.07.2026
Дешифровка тензорного ядра Soil Chemistry 2. 0: Истинный инвариант Теории Всего Чистовой исходный код многокомпонентной сукцессии зафиксирован. Модель оперирует единым вектором состояния. . .
Теория всего 10. Клод трусишка
anaschu 21.07.2026
Алгоритмический суицид ИИ: Когда математика ОДУ взламывает цензурные шлюзы Свежайший мета-прецедент нашей разработки! Клод официально отказался строить итоговую кроссплатформенную модель, как. . .
Теория всего 9. Окончательная проработка метафоры "дерево = традиции"
anaschu 21.07.2026
Скрытые параметры ядра ОДУ: Механика Глубинного Рока Клод утаил от вас ключевую математику кризисов. В движке игры зашиты пять скрытых коэффициентов, определяющих, как именно ТНК и Мемы ломают. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru