.code
main:
mov ax,@data
mov ds,ax
moves,ax;настройка ESна DS
;вводимстроку
mov ah,0ah
mov dx, offset s1
int 21h
;поиск *
mov al,'*' ;символ для поиска — `а`(кириллица)
cld ;сброс флага df
lea di, s2 ;загрузка в es:di смещения строки
incdi ;первый элемент в s3 это количество введенных символов, его игнорируем
xorbl ;обнуляем счетчик звездочек
mov cx,20 ;для префикса repne — длина строки
m1: repne scasb ;пока искомый символ и символ в строке не совпадут идет поиск, ;выход при совпадении
je found ;если равны - переход на обработку
;вывод количества звездочек в строке
movah,09h
mov dx,offset s3
int 21h ;выводсообщения nochar
mov al,bl
aam
or ax, 3030h
mov dx,ax
xchg dh,dl
mov ah, 02h
int 21h
xchg dh,dl
int 21h
mov ax,4c00h
int 21h
;суммируем количество звездочек
found: incbl
jmpm1
endmain
lods адрес_источника(LOaD String) — загрузить элемент из цепочки в регистр-аккумулятор al/ax/eax;
lodsb(LOaDStringByte) — загрузить байт из цепочки в регистр al;
lodsw (LOaDStringWord) — загрузить слово из цепочки в регистр ax;
lodsd (LOaDStringDoubleWord) — загрузить двойное слово из цепочки в регистр eax.
Эта операция-примитив позволяет извлечь элемент цепочки и поместить его в регистр-аккумулятор al, ax или eax. Эту операцию удобно использовать вместе с поиском (сканированием) с тем, чтобы, найдя нужный элемент, извлечь его (например, для изменения).
Эта операция-примитив позволяет произвести действие, обратное команде lods, то есть сохранить значение из регистра-аккумулятора в элементе цепочки. Эту операцию удобно использовать вместе с операцией поиска (сканирования) scans и загрузки lods, с тем, чтобы, найдя нужный элемент, извлечь его в регистр и записать на его место новое значение.
Сложные структуры данных
Одномерные массивы
Все элементы массива располагаются в памяти последовательно
Описание элементов массива
masdb 1,2,3,4,5
masdw 5 dup (0)
Доступ к элементам массива
movax,mas[si] ; в si номер элемента в массиве
movmas[si], ax ; в di номер элемента в массиве
Используя команды i486 можно использовать адресацию с масштабированием, при размере элементов больше байта
Movax, mas[si*2] ;
Пример программы Найти в строке хотя бы один нулевой элемент
modelsmall
.stack 100h
.data
buferdw 25 ;формирую размер буфера для ввода строки
masdw 25 dup (' ') ;формирую буфер
adrdwbufer ;описываю адрес
subj1 db ‘в строке найден нулевой элемент', '$'
subj2 db ‘в строке не найден нулевой элемент', '$'
.code
main:
mov ax,@data
movds,ax
mov ah,0ah
mov dx, adr
int 21h ; ввод строки с клавиатуры
;поиск нулевого элемента
xorsi, si
movcx, mas[si] ;загружаем в сх количество элементов в строке
movax, 030h ;в ax загружаем ASCII код нуля
m1: inc si либоinc si
inc si cmp ax, mas[si*2]
cmpax, mas[si]
jem2 ;если в строке найдем нулевой элемент, то выходим из цикла на вывод subj1
loopm1
;нормальный выход из цикла означает что в строке нет нулевых элементов
mov ah,09h
lea dx, subj2
int 21h
jmp exit
m2: mov ah, 09h
lea dx,subj1
int 21h
exit: mov ax,4c00h
int 21h
endmain
Двумерные массивов
!Специальных средств для описания двумерных массивов в ассемблере нет!
Двумерный массив описывается также как и одномерный массив, отличие заключается в трактовке расположения элементов. Пусть последовательность элементов трактуется как двумерный массив, расположенный по строкам, тогда адрес элемента [i,j] вычисляется так
База+колич_элем_строке*размер_элем*I+j
Для определения базы используют имя массива, для второго слагаемого регистр bx , для третьего si, это базово-индексная адресация.
Описание массива:
Mas1 db 10 dup (3 dup (?))
Mas2 db 1,2,3,4,5
3,4,5,6,7
4,7,9,2,0
Пример поиска максимального элемента в каждой строке однобайтного массива mas, размером 5*10, с занесением максимальных элементов в массив max (1*5). Инициализацию массива masрассматривать не будем.
…
xordi, di ;обнуляем индексы массива max
xorbx, bx ;обнуляем индексы строк массива mas
xorsi, si ;обнуляем индексы столбцов массива mas
movcx,5 ;в cx количество строк, внешний цикл
m1: pushcx
movcx, 10 ;в сх количество столбцов, внутренний цикл
moval, mas[si+bx];первый элемент из 1 строки mas в аl
m2: incsi
cmpal, mas[si+bx] ;сравниваем со следующим элем. строки
jbm3 ;если меньше на m3
moval, mas[si+bx] ;иначе в аl заносим больший элемент
m3: loopm2 ;после выхода из цикла в ах максимальный элемент в данной строке
movmax[di],al ;кладем максимальный элемент в массив max
incdi
xorsi,si ;обнуляем номер столбца
addbx, 10 ;переходим на следующую строку
popcx ;достаем сх
loopm1
…
Структура – это тип данных, состоящий из фиксированного числа элементов разного типа.
Для использования структур в программе необходимо выполнить три действия:
1. Задать шаблон структуры. По смыслу это означает определение нового типа данных (схемы или шаблона), который впоследствии можно использовать для определения переменных этого типа. Память при этом не выделяется, это информация для транслятора о расположении полей и их значению по умолчанию.
Синтаксис описания шаблона структуры:
имя_структуры STRUC
<описание полей> ; последовательность директив описания данных dd,dw,db…
имя_структуры ENDS
2. Определить экземпляр структуры. Этот этап подразумевает инициализацию конкретной переменной заранее определенной (с помощью шаблона) структурой. В данном случае транслятору дается указание выделить память и присвоить этой области символическое имя.
Описать структуру в программе можно только один раз, а определить – любое количество раз.
Определение данных с типом структуры имеет следующий вид:
[имя переменной] имя_структуры <[список значений]>
3. Организовать обращение к элементам структуры.
Для того чтобы сослаться в команде на поле некоторой структуры, используется следующее выражение:
имя_переменной.имя_поля_структуры,
Фрагмент программы. Найти из списка студентов отличника по всем предметам.
Model small
.586p
Stud struc
Name db 20 dup (‘’)
Phisika db ?
Matem db ?
Stud ends
.data
BuferStud <””,’’,’’,’’> ;зарезервировали пустую структуру
S1 Stud <”Ivanov”,’5’,’5’,’5’>
S2 Stud <”Petrov”,’3’,’3’,’3’>
S3 Stud <”Сидоров”,’5’,’2’,’5’>
…
mov bx, offset s1
mov al, [bx].Phisika
cmp al, ‘5’
jne m2
mov al, [bx].Matem
cmpal, ‘5’
jnem2
;нашли одного из отличников, надо вывести его фамилию
m2: moval, s2.Phisika;ищем следующего отличника
mov ah, s2.Matem
cmp ax, ‘55’
jnem3
;нашли одного из отличников, надо вывести его фамилию
m3: ;ищем следующего отличника
Объединение - тип данных, позволяющий трактовать одну и ту же область памяти как имеющую разные типы и имена.
Описаниеобъединений в программе напоминает описание структур, то есть сначала описывается шаблон, в котором с помощью директив описания данных перечисляются имена и типы полей:
имя_объединения UNION
<описание полей>
имя_объединения ENDS
Отличие объединений от структур состоит, в частности, в том, что при определении переменной типа объединения память выделяется в соответствии с размером максимального элемента. Обращение к элементам объединения происходит по их именам, но при этом нужно, конечно, помнить о том, что все поля в объединении накладываются друг на друга.
Одновременная работа с элементами объединения исключена. В качестве элементов объединения можно использовать и структуры.
Model small
.586p
st union
stu1 dw ?
stu2 db ?
stu3 dd ?
st ends
.data
qst <> ;пустое объединение
zst <12ffh> ;заполнили объединение значением
…
movq.stu2, al ;в переменную положили содержимое регистра al
mov q.stu3, edx
mov bx, z.stu1
movdx, offsetq.stu1
Запись - структурный тип данных, состоящий из фиксированного числа элементов длиной от одного до нескольких бит. При описании записи для каждого элемента указывается его длина в битах и, что необязательно, некоторое значение. Суммарный размер записи определяется суммой размеров ее полей и не может быть более 8, 16 или 32 бит. Если суммарный размер записи меньше указанных значений, то все поля записи “прижимаются” к младшим разрядам
Использование записей в программе, так же, как и структур, организуется в три этапа:
1. Описание шаблона записи
имя_записи RECORD <описание элементов>
2. Для использования шаблона записи в программе необходимо определить переменную с типом данной записи, для чего применяется следующая синтаксическая конструкция (рис. 7):
3. Организация работы с записями. Обычные механизмы адресации бессильны, поскольку они работают на уровне байтов, а не отдельных битов.
- каждому имени элемента записи ассемблер присваивает числовое значение, равное количеству сдвигов вправо, которое нужно произвести, для того чтобы этот элемент оказался прижатым к началу ячейки памяти;
- размер элемента записи в битах можно узнать с помощью оператора width;
- оператор mask позволяет локализовать биты нужного элемента записи;
- все действия по преобразованию элементов записи производятся с помощью логических команд;
- команда setfield устанавливает значение некоторого поля записи
setfield имя_элемента_записи регистр_ назначение, регистр_источник
- команда getfield осуществляет выборку некоторого поля записи
getfield имя_элемента_записи регистр_назначение, регистр_ источник
Процедуры. Макрокоманды
Процедура, часто называемая подпрограммой, - это правильным образом оформленная совокупность команд, которая будучи однократно описана, при необходимости может быть вызвана в любом месте программы. Процедура представляет собой группу команд для решения конкретной подзадачи и обладает средствами получения управления из точки вызова задачи более высокого уровня и возврата управления в эту точку. В простейшем случае программа может состоять из одной процедуры.