- •4) Mov esi,6*2 ; 2 байта – размер элементов
- •Индексная адресация со смещением — режим адресации, при котором полный адрес формируется из двух компонентов:
- •Базовая индексная адресация со смещением — режим адресации, при котором полный адрес формируется максимум из трех компонентов:
- •Xor ecx,ecx ;обнуление есx
- •Структуры
- •Организовать обращение к элементам структуры.
- •Цепочечные команды или команды обработки строк символов
- •Организация обращения к элементам записи.
- •Работа с записями
- •1) Для выделения элемента записи необходимо:
- •2) Чтобы поместить измененный элемент на его место в запись необходимо:
- •3. В конце работы файл следует закрыть.
- •4. Признаком ошибки при выполнении функции dos является взведенный флаг с (переноса).
- •2. Создание файла с усечением существующего до нулевой длины.
- •LpFileName — указатель на asciiz-строку с именем (путем) открываемого или создаваемого файла;
- •DwDesiredAccess — тип доступа к файлу:
- •3) Создать и открыть новый файл
- •4) Чтение из файла или устройства
- •5) Переместить указатель чтения/записи
- •1) HFile – хэндл того файла, в котором перемещается указатель.
- •7) Запись в файл или устройство
- •8) Закрыть файл
- •9) Удаление файла
- •Функция 01h – ожидание ввода символа с эхопечатью
- •Функция 0ah – получение строки символов
- •1) Создать каталог
- •2) Удалить каталог
- •5) Определить текущий каталог
- •Перечень функций прерывания 21h, работающих с файлами, которые имеют длинные имена и соответствующие функции api Win32.
- •Перечислим функции api Win32, имеющие отношение к работе с файловой системой.
- •1) В Win32 получить время создания, время последнего доступа и время последней модификации файла можно с помощью функции GetFileTime.
- •3) В Win32 имеется функция GetFileInformationByHandle, с помощью которой можно получить все атрибуты файла:
- •Обзор прерываний bios
- •Int 10h, функция 0Dh. Чтение пиксела.
- •02H/03h - Чтение/запись секторов.
- •Прямое программирование видеобуфера в текстовом режиме
- •Текстовый режим. Доступ к памяти
- •Организация памяти в графическом режиме 12h
- •Вычисление адреса Пикселя по экранным координатам.
- •Рисование с помощью регистров Графического Контроллера
- •Установка цвета отдельных пикселей.
- •Прокрутка областей экрана, копирование областей экрана.
- •Чтение отдельных пикселей с экрана.
- •Рисование с помощью регистров Указателя Последовательности
- •Установка цвета ячейки пикселей.
Лекция №8. Массивы, структуры, записи, объединения
Пересылка данных с помощью команды xlat
Команда: |
XLAT адрес XLATB |
Назначение: |
Трансляция в соответствии с таблицей |
Помещает в AL байт из таблицы в памяти по адресу ES:BX (или ES:EBX) со смещением относительно начала таблицы, равным AL.
В качестве аргумента для XLAT в ассемблере можно указать имя таблицы, но эта информация никак не используется процессором и служит только как комментарий. Если этот комментарий не нужен, можно применить форму записи XLATB.
Пример: Преобразовать шестнадцатеричное число в ASCII-код соответствующего ему символа:
.data
htable db "0123456789ABCDEF"
.code
….
mov al,0Ch
mov bx, offset htable
xlat
После выполнения команды xlat, регистр AL будет содержать не число 0Сh, а ASCII-код буквы «С».
Пример 3: Заполнить массив из 30-ти элементов размером в байт значениями индексов. Вывести массив на экран в одну строку, учитывая, что элементы массива максимум двухзначные числа.
.386
.model flat, stdcall
includelib import32.lib
extrn ExitProcess:PROC
extrn MessageBoxA:PROC
.data
Ttl db 'Massiv',0h
mas db 30 dup (?) ; 32 элементов массива + 10 символов +переходы на
; следующую строчку 2 байта 0ah,0dh
db 0ah
mes1 db 'Massiv: ',0ah,0dh
masVivod db 85 dup (?) ; 10 элементов массива + 10 символов +переходы на
; следующую строчку 2 байта 0ah,0dh
i db 0
N db 30
tabl db 30h,31h,32h,33h,34h,35h,36h,37h,38h,39h
.code
start:
xor ecx,ecx ;обнуление есx
xor edx,edx
mov cl,N ;значение счетчика цикла в cl
mov esi, 0 ;индекс начального элемента в si
;-------------------------------------------------------------------------------------------------
; Заполнение элементов массива значениями их индексов
go:
mov bh,i
mov mas[esi],bh
inc esi
inc i
loopnz go
;-------------------------------------------------------------------------------------------------
mov cl,N
mov edi,0
mov esi,0
;-------------------------------------------------------------------------------------------------
; Проверяем число больше или равно 10, если «да», то уходим на метку met1 и
; выводим его как двузначное число. Если число меньше 10 (однозначное),
; то уходим на метку met2.
go1: ; цикл инициализации
xor eax,eax
mov al,mas[edi]
cmp al,0ah
jae met1
jmp met2
;-------------------------------------------------------------------------------------------------
; Формируем двузначное число в массив masVivod. Делим его на 10, чтобы
; отделить первую цифру и получить одну цифру в остатке. Переводим первую
; цифру и остаток в ASCII код
met1:
mov bl,10
div bl
mov ebx, offset tabl
xlat
mov masVivod[esi],al
inc esi
mov al,ah
xlat
mov masVivod[esi],al
jmp met3
;-------------------------------------------------------------------------------------------------
; Если число однозначное, то заменяем число на символ
; числа и записываем символ числа (ASCII код числа) в регистр al
met2:
mov ebx, offset tabl
xlat
mov masVivod[esi],al
;-------------------------------------------------------------------------------------------------
; Ставим после числа символ «;» и наращиваем индексы
met3:
inc esi
mov masVivod[esi],';'
inc esi
inc edi
loopnz go1
mov masVivod[esi],0h
;вывод на экран получившегося массива
push 0h
push offset Ttl
push offset mes1
push 0h
call MessageBoxA
push 0h
call ExitProcess
end start
Результат:
Пример 5: Вывести в одну строку все значения элементов массива, учитывая, что значения элементов массива могут быть трёхзначными и имеют размер в один байт. Значение элементов массива сформировать как i*k, i=k.
.386
.model flat, stdcall
includelib import32.lib
extrn ExitProcess:PROC
extrn MessageBoxA:PROC
.data
Ttl db 'Massiv',0h
mas db 30 dup (?) ; 32 элементов массива + 10 символов +переходы на
; следующую строчку 2 байта 0ah,0dh
mes1 db 'Massiv: ',0ah,0dh
masVivod db 85 dup (?) ; 10 элементов массива + 10 символов +переходы на
; следующую строчку 2 байта 0ah,0dh
i db 0
k db 0
N db 16 ; Максимальное значение элемента массива 15*15=225
tabl db 30h,31h,32h,33h,34h,35h,36h,37h,38h,39h
.code
start:
xor ecx,ecx
xor edx,edx
mov cl,N
mov esi, 0
go:
mov bl,i
mov al,k
mul bl
mov mas[esi],al
inc esi
inc i
inc k
loopnz go
mov cl,N
mov edi,0
mov esi,0
; ----------------------------------------------------------------------------------------------
; Проверяем число. Если оно однозначное, то уходим на метку met2. Если число
; двухзначное, то уходим на метку met1. Если число трёхзначное, то продолжаем
; выполнять код программы.
go1:
xor eax,eax
mov al,mas[edi]
cmp al,0ah
jb met2
cmp al,64h
jb met1
; Если число трёхзначное, то делим его на 10, чтобы
; получить две первых цифры числа и остаток. Заносим в регистр целую часть от деления
; а остаток переводим в ASCII код. Оставшиеся две цифры числа (целую часть от
; деления) сохраняем в регистре ah и переходим на метку met4.
mov bl,10
div bl
mov ebx, offset tabl
xchg al,ah
xlat
mov masVivod[esi+2],al
mov al,ah
xor ah,ah
jmp met4
; ---------------------------------------------------------------------------------------------
; Если число двухзначное, то делим его на 10, чтобы
; получить первую цифру числа и остаток. Заносим в память первую цифру и
; остаток.
met1:
mov bl,10
div bl
mov ebx, offset tabl
xchg al,ah
xlat
mov masVivod[esi+1],al
mov al,ah
xlat
mov masVivod[esi],al
inc esi
jmp met3
met4:
mov bl,10
div bl
mov ebx, offset tabl
xchg al,ah
xlat
mov masVivod[esi+1],al
mov al,ah
xlat
mov masVivod[esi],al
inc esi
inc esi
jmp met3
; ----------------------------------------------------------------------------------------------
; Имеем однозначное число. Записываем ASCII код этого числа в память.
met2:
mov ebx, offset tabl
xlat
mov masVivod[esi],al
; ----------------------------------------------------------------------------------------------
; Ставим после числа в памяти символ «;» в качестве разделителя.
met3:
inc esi
mov masVivod[esi],';'
inc esi
inc edi
loop go1
mov masVivod[esi],0h
;------------------------------------------------------------
;вывод на экран получившегося массива
push 0h
push offset Ttl
push offset mes1
push 0h
call MessageBoxA
push 0h
call ExitProcess
end start
Результат:
_______________________________________________________________
Самостоятельно на практике: Вывести все значения элементов массива в несколько строк. В каждой строке должно быть по 5 элементов массива. Значения элементов массива могут быть трёхзначными размером в байт.
Доступ к элементам массива
Все элементы массива располагаются в памяти компьютера последовательно и то, как трактовать данную последовательность решает программист.
Одну и ту же область памяти можно трактовать как одномерный массив, и одновременно те же самые данные могут трактоваться как двумерный массив. Все зависит только от алгоритма обработки этих данных в конкретной программе.
Эти же соображения можно распространить и на индексы элементов массива.
Наример, в программе статически определена последовательность данных:
Mas dw 0,1,2,3,4,5,456,876,7,8752 ; 00 00 00 01 00 02 00 03 00 04
; 00 05 01 С8 03 6С 00 07 22 30
Организовать доступ к предпоследнему байту можно следующим образом:
1) Mas[19] ; =30
2) Mas[13h] ; =C8
3) Mov esi,19
Mas[esi] ; =30
4) Mov esi,6*2 ; 2 байта – размер элементов
Mov ax, Mas[esi] ; ax=01C8
Пусть эта последовательность чисел трактуется как одномерный массив. Размерность каждого элемента определяется директивой dw.
В общем случае для получения адреса элемента в массиве необходимо начальный (базовый) адрес массива сложить с произведением индекса (номер элемента минус единица) этого элемента на размер элемента массива:
база + (индекс*размер элемента)
Способы адресации, используемые при работе с массивами
-
Индексная адресация со смещением — режим адресации, при котором полный адрес формируется из двух компонентов:
-
постоянного (базового) — указанием прямого адреса массива в виде имени идентификатора, обозначающего начало массива (смещения);
-
переменного (индексного) — указанием имени индексного регистра.
К примеру:
mas dw 0,1,2,3,4,5
...
mov si,4
;поместить 3-й элемент массива mas в регистр ax:
mov ax,mas[si]
-
Базовая индексная адресация со смещением — режим адресации, при котором полный адрес формируется максимум из трех компонентов:
-
постоянного (необязательного компонента), в качестве которого может выступать прямой адрес массива в виде имени идентификатора (смещение), или непосредственное значение;
-
переменного (базового) — указанием имени базового регистра;
-
переменного (индексного) — указанием имени индексного регистра.
-
Этот вид адресации используется при обработке двухмерных массивов. Например:
Mov eax,mas[bx][si]
В качестве базового регистра может использоваться любой из восьми регистров общего назначения. В качестве индексного регистра также можно использовать любой регистр общего назначения, за исключением esp/sp.
Микропроцессор позволяет масштабировать индекс. Необходимость в масштабировании возникает при работе с массивами, которые имеют размер элементов, равный 2, 4 или 8 байтам.
Например: Разработать программу, в которой просматривается массив, состоящий из слов, и производится сравнение этих элементов с нулем. Выводится соответствующее сообщение.
Пример 6: Просмотр массива слов с использованием масштабирования
;prg_12_2.asm. Для DOS16.
MASM
MODEL small
STACK 256
.data ;начало сегмента данный
;тексты сообщений:
mes1 db "не равен 0!$",10,13
mes2 db "равен 0!$",10,13
mes3 db 10,13,'Элемент $'
mas dw 2,7,0,0,1,9,3,6,0,8 ;исходный массив
.code
;.486 ;это обязательно
start:
mov ax,@data
mov ds,ax ;связка ds с сегментом данных
xor ax,ax ;обнуление ax
prepare:
mov сx,10 ;значение счетчика цикла в cx
mov esi,0 ;индекс в esi
compare:
mov dx,mas[esi*2] ;первый элемент массива в dx
cmp dx,0 ;сравнение dx с 0
je equal ;переход, если равно
not_equal: ;не равно
mov ah,09h ;вывод сообщения на экран
lea dx,mes3
int 21h
mov ah,02h ;вывод номера элемента массива на экран
mov dx,si
add dl,30h
int 21h
mov ah,09h
lea dx,mes1
int 21h
inc esi ;на следующий элемент
dec сх ;условие для выхода из цикла
jcxz exit ;cx=0? Если да - на выход
jmp compare ;нет - повторить цикл
equal: ;равно 0
mov ah,09h ;вывод сообщения mes3 на экран
lea dx,mes3
int 21h
mov ah,02h
mov dx,si
add dl,30h
int 21h
mov ah,09h ; вывод сообщения mes2 на экран
lea dx,mes2
int 21h
inc esi ;на следующий элемент
dec ex ;все элементы обработаны?
jcxz exit
jmp compare
exit:
mov ax,4c00h ;стандартный выход
int 21h
end main ;конец программы
Возможны следующие случаи при адресации массивов:
-
если для описания адреса используется только один регистр, то такая адресация называется базовой адресацией и этот регистр рассматривается как базовый:
; переслать байт из области данных, адрес которой находится в
; регистре ebx
mov al,[ebx]
2) если для задания адреса в команде используется прямая адресация (в виде идентификатора) в сочетании с одним регистром, то такая адресация называется индексной адресацией. Регистр считается индексным и поэтому можно использовать масштабирование для получения адреса нужного элемента массива:
;сложить содержимое eax с двойным словом в памяти по адресу
; mas + (ebx)*4
add eax,mas[ebx*4]
-
если для описания адреса используются два регистра, то такая адресация называется базово-индексной адресацией. Левый регистр рассматривается как базовый, а правый — как индексный.
Базово-индексную адресацию можно сочетать с прямой адресацией или указанием непосредственного значения. Адрес тогда будет формироваться как сумма всех компонентов.
К примеру:
mov ax,mas[ebx][ecx*2]
;адрес операнда равен [mas+(ebx)+(ecx)*2]
...
sub dx,[ebx+8][ecx*4]
;адрес операнда равен [(ebx)+8+(ecx)*4]
Масштабирование эффективно только, когда размерность элементов массива равна 2, 4 или 8 байтам. Если же размерность элементов другая, то организовывать обращение к элементам массива нужно обычным способом.
Пример 7: Обработка массива элементов с нечетной длиной. Размер элемента массива в три байта. Массив сформировать самостоятельно, следующим образом: первый элемент массива равен Е3 1111h=14 881 041d, все последующие трёхбитные элементы массива равны inc(E3 1111h). В памяти сформировать массив из 16 трёхбитных элемента. Увеличить на единицу в каждом элементе массива значение первого байта. Вывести измененный массив на экран в одну строку. Примечание: Е4 1111h=14 946 577d.
;---------------------------------------------------------------------------
; Версия для Win32 (tri.asm)
.386
.model flat, stdcall
includelib import32.lib
extrn ExitProcess:PROC
extrn MessageBoxA:PROC
.data
Ttl db 'Massiv',0h
mas db 16 dup (3 dup (0)) ; 48 элементов в массиве
; следующую строчку 2 байта 0ah,0dh
mes1 db 'Massiv: ',0ah,0dh
Msg db 150 dup (?)
masVivod db 85 dup (?) ;
var dd 0E31111h
var2 dd ?
var3 dd 00000000h
i db 1
N db 16
tabl db 30h,31h,32h,33h,34h,35h,36h,37h,38h,39h
k dd 0
.code
start: