Tooprogram.ru

Компьютерный справочник
0 просмотров
Рейтинг статьи
1 звезда2 звезды3 звезды4 звезды5 звезд
Загрузка...

Массивы в ассемблере примеры

Архитектура компьютера

Введение
Теоретическая часть
1Архитектура компьютера
Лабораторный практикум
1Создание программы на языке ассемблера
2Применение функций DOS и BIOS
3Линейные алгоритмы
4Десятичная арифметика
5Команды передачи управления
6Циклы с условием
7Циклы со счетчиком
8Работа с массивами
9Цепочечные команды
Приложения
1Таблица кодов символов ASCII
2Функции DOS и BIOS
Гостевая книга

Лабораторная работа №8

Работа с массивами

Вопросы для повторения:

  1. Для каких данных целесообразно использовать массивы?
  2. Как организуется работа с массивами в языках высокого уровня?
  3. Какие алгоритмы существуют для сортировки массивов и поиска элементов в них?

В языке ассемблера не существует специальных средств для организации работы с массивами. Массивы описываются в виде последовательности элементов нужной размерности; работа с ними ведется с использованием методов косвенной адресации.

Пример: Задан массив. Вывести на экран сумму его элементов.

1data segment
2mas db 12, 2, 7, 3, 2, 0, 21, 9, 0, 16;исходный массив
3len dw $-mas;размер массива в байтах
4data ends
5
6code segment
7start:
8assume cs:code, ds: data
9mov ax, data
10mov ds, ax
11
12lea bx, mas;берём в bx адрес первого элемента
13mov cx, len;счетчик цикла
14xor ax, ax
15cikl:add al, [ bx ];прибавляем к al байт, адрес которого хранится в bx
16inc bx;переходим к следующему элементу
17loop cikl
18
19aam;преобразуем сумму в BCD-код
20add ax, 3030h;затем в ASCII-код
21mov bx, ax;и выводим
22mov ah, 02
23mov dl, bh
24int 21h
25mov dl, bl
26int 21h
27
28mov ax, 4c00h
29int 21h
30code ends
31end start

При обработке не байтовых массивов следует учитывать размер элементов. Так в приведенном выше примере в строке 3 вычисляется размер массива в байтах, и в строке 13 он берётся за количество элементов. Для массива слов это значение придется поделить на 2. В строке 16 для перехода к следующему элементу используется простой инкремент адреса, для массива слов эта строка может выглядеть так: add bx, 2 .

Assembler

Изучение с «нуля»

суббота, 6 июня 2009 г.

Данные сложного типа. Массивы.

Массив — структурированный тип данных, состоящий из некоторого числа элементов одного типа.

Для того чтобы разобраться в возможностях и особенностях обработки массивов в программах на ассемблере, нужно ответить на следующие вопросы:

  • Как описать массив в программе?
  • Как инициализировать массив, то есть как задать начальные значения его элементов?
  • Как организовать доступ к элементам массива?
  • Как организовать массивы с размерностью более одной?
  • Как организовать выполнение типовых операций с массивами?

Описание и инициализация массива в программе

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

1) Перечислением элементов массива в поле операндов одной из директив описания данных. При перечислении элементы разделяются запятыми. К примеру:

;массив из 5 элементов.Размер каждого
элемента 4 байта:
mas dd 1,2,3,4,5

2) Используя оператор повторения dup. К примеру:

;массив из 5 нулевых элементов.
;Размер каждого элемента 2 байта:
mas dw 5 dup (0)

Такой способ определения используется для резервирования памяти с целью размещения и инициализации элементов массива.

3) Используя директивы label и rept . Пара этих директив может облегчить описание больших массивов в памяти и повысить наглядность такого описания. Директива rept относится к макросредствам языка ассемблера и вызывает повторение указанное число раз строк, заключенных между директивой и строкой endm . К примеру, определим массив байт в области памяти, обозначенной идентификатором mas_b. В данном случае директива label определяет символическое имя mas_b, аналогично тому, как это делают директивы резервирования и инициализации памяти. Достоинство директивы label в том, что она не резервирует память, а лишь определяет характеристики объекта. В данном случае объект — это ячейка памяти. Используя несколько директив label, записанных одна за другой, можно присвоить одной и той же области памяти разные имена и разный тип, что и сделано в следующем фрагменте:

.
n=0
.
mas_b label byte
mas_w label word
rept 4
dw 0f1f0h
endm

В результате в памяти будет создана последовательность из четырех слов f1f0. Эту последовательность можно трактовать как массив байт или слов в зависимости от того, какое имя области мы будем использовать в программе — mas_b или mas_w.

4) Использование цикла для инициализации значениями области памяти, которую можно будет впоследствии трактовать как массив.
Посмотрим на примере, каким образом это делается.

;prg_12_1.asm
MASM
MODEL small
STACK 256
.data
mes db 0ah,0dh,’Массив- ‘,’$’
mas db 10 dup (?) ;исходный массив
i db 0
.code
main:
mov ax,@data
mov ds,ax
xor ax,ax ;обнуление ax
mov cx,10 ;значение счетчика цикла в cx
mov si,0 ;индекс начального элемента в cx
go: ;цикл инициализации
mov bh,i ;i в bh
mov mas[si],bh ;запись в массив i
inc i ;инкремент i
inc si ;продвижение к следующему
;элементу массива
loop go ;повторить цикл
;вывод на экран получившегося массива
mov cx,10
mov si,0
mov ah,09h
lea dx,mes
int 21h
show:
mov ah,02h ;функция вывода значения
;из al на экран
mov dl,mas[si]
add dl,30h ;преобразование числа в символ
int 21h
inc si
loop show
exit:
mov ax,4c00h ;стандартный выход
int 21h
end main ;конец программы

Доступ к элементам массива

При работе с массивами необходимо четко представлять себе, что все элементы массива располагаются в памяти компьютера последовательно.
Само по себе такое расположение ничего не говорит о назначении и порядке использования этих элементов. И только лишь программист с помощью составленного им алгоритма обработки определяет, как нужно трактовать эту последовательность байт, составляющих массив. Так, одну и ту же область памяти можно трактовать как одномерный массив, и одновременно те же самые данные могут трактоваться как двухмерный массив. Все зависит только от алгоритма обработки этих данных в конкретной программе. Сами по себе данные не несут никакой информации о своем “смысловом”, или логическом, типе. Помните об этом принципиальном моменте.
Эти же соображения можно распространить и на индексы элементов массива. Ассемблер не подозревает об их существовании и ему абсолютно все равно, каковы их численные смысловые значения.
Для того чтобы локализовать определенный элемент массива, к его имени нужно добавить индекс. Так как мы моделируем массив, то должны позаботиться и о моделировании индекса. В языке ассемблера индексы массивов — это обычные адреса, но с ними работают особым образом. Другими словами, когда при программировании на ассемблере мы говорим об индексе, то скорее подразумеваем под этим не номер элемента в массиве, а некоторый адрес.

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

dim dw 0011h,2233h,4455h,6677h,8899h

Пусть эта последовательность чисел трактуется как одномерный массив. Размерность каждого элемента определяется директивой dw , то есть она равна 2 байта . Чтобы получить доступ к числу 6677h, нужно к адресу массива прибавить 6. Нумерация элементов массива в ассемблере начинается с нуля.
В общем случае для получения адреса элемента в массиве необходимо начальный (базовый) адрес массива сложить с произведением индекса этого элемента на размер элемента массива:

база + (индекс*размер элемента)

Архитектура микропроцессора предоставляет достаточно удобные программно-аппаратные средства для работы с массивами. К ним относятся базовые и индексные регистры, позволяющие реализовать несколько режимов адресации данных. Используя данные режимы адресации, можно организовать эффективную работу с массивами в памяти.
Для более глубокого понимания можно помедитировать на эту програмку:

Эта программа ни чего не выводит на экран. Предназначена просто для медитации на нее под отладчиком. Внимание. При отладке, чтобы увидеть работу цикла, на команде loop go, нужно нажимать клавишу F7.
Зарисовка из медитации на эту прогу:

Двухмерные массивы

С представлением одномерных массивов в программе на ассемблере и организацией их обработки все достаточно просто. А как быть если программа должна обрабатывать двухмерный массив? Все проблемы возникают по-прежнему из-за того, что специальных средств для описания такого типа данных в ассемблере нет. Двухмерный массив нужно моделировать. На описании самих данных это почти никак не отражается — память под массив выделяется с помощью директив резервирования и инициализации памяти.

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

Если последовательность однотипных элементов в памяти трактуется как двухмерный массив, расположенный по строкам, то адрес элемента (i, j) вычисляется по формуле

(база + количество_элементов_в_строке * размер_элемента * i+j)

Здесь i = 0. n–1 указывает номер строки, а j = 0. m–1 указывает номер столбца.

Например, пусть имеется массив чисел (размером в 1 байт) mas(i, j) с размерностью 4 на 4
(i= 0. 3, j = 0. 3):

23 04 05 67
05 06 07 99
67 08 09 23
87 09 00 08

В памяти элементы этого массива будут расположены в следующей последовательности:

23 04 05 67 05 06 07 99 67 08 09 23 87 09 00 08

Если мы хотим трактовать эту последовательность как двухмерный массив, приведенный выше, и извлечь, например, элемент
mas(2, 3) = 23, то проведя нехитрый подсчет, убедимся в правильности наших рассуждений:

Эффективный адрес mas(2, 3) = mas + 4 * 1 * 2 + 3 = mas + 11

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

Эта программа, тоже ни чего не выводит, так как предназначена для выполнения ее под отладчиком, для пущего научения.

Массивы на языке ассемблера

Дадим формальное определение:

массив — структурированный тип данных, состоящий из некоторого числа элементов одного типа.

Для того чтобы разобраться в возможностях и особенностях обработки массивов в программах на ассемблере, нужно ответить на следующие вопросы:

  1. Как описать массив в программе?
  2. Как инициализировать массив , то есть как задать начальные значения его элементов?
  3. Как организовать доступ к элементам массива?
  4. Как организовать массивы с размерностью более одной?
  5. Как организовать выполнение типовых операций с массивами?

Описание и инициализация массива в программе

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

;массив из 5 элементов.Размер каждого элемента 4 байта:

  1. Используя оператор повторения dup . К примеру:

;массив из 5 нулевых элементов.

;Размер каждого элемента 2 байта:

Такой способ определения используется для резервирования памяти с целью размещения и инициализации элементов массива.

  1. Используя директивы label и rept . Пара этих директив может облегчить описание больших массивов в памяти и повысить наглядность такого описания. Директива rept относится к макросредствам языка ассемблера и вызывает повторение указанное число раз строк, заключенных между директивой и строкой endm. К примеру, определим массив байт в области памяти, обозначенной идентификатором mas_b. В данном случае директива label определяет символическое имя mas_b, аналогично тому, как это делают директивы резервирования и инициализации памяти. Достоинство директивы label в том, что она не резервирует память, а лишь определяет характеристики объекта. В данном случае объект — это ячейка памяти. Используя несколько директив label , записанных одна за другой, можно присвоить одной и той же области памяти разные имена и разный тип, что и сделано в следующем фрагменте:

mas_b label byte

mas_w label word

В результате в памяти будет создана последовательность из четырех слов f1f0 . Эту последовательность можно трактовать как массив байт или слов в зависимости от того, какое имя области мы будем использовать в программе — mas_b или mas_w.

Листинг 2 Инициализация массива в цикле

mes db 0ah,0dh,’ Массив — ‘,’$’

mas db 10 dup (?) ;исходный массив

xor ax,ax ;обнуление ax

mov cx,10 ;значение счетчика цикла в cx

mov si,0 ;индекс начального элемента в cx

go: ;цикл инициализации

mov mas[si],bh ;запись в массив i

inc i ;инкремент i

inc si ;продвижение к следующему элементу массива

loop go ;повторить цикл

;вывод на экран получившегося массива

mov ah,02h ;функция вывода значения из al на экран

add dl,30h ;преобразование числа в символ

mov ax,4c00h ;стандартный выход

end main ;конец программы

Доступ к элементам массива

При работе с массивами необходимо четко представлять себе, что все элементы массива располагаются в памяти компьютера последовательно.

Само по себе такое расположение ничего не говорит о назначении и порядке использования этих элементов. И только лишь программист с помощью составленного им алгоритма обработки определяет, как нужно трактовать эту последовательность байт, составляющих массив. Так, одну и ту же область памяти можно трактовать как одномерный массив, и одновременно те же самые данные могут трактоваться как двухмерный массив. Все зависит только от алгоритма обработки этих данных в конкретной программе. Сами по себе данные не несут никакой информации о своем “смысловом”, или логическом, типе. Помните об этом принципиальном моменте.

Эти же соображения можно распространить и на индексы элементов массива . Ассемблер не подозревает об их существовании и ему абсолютно все равно, каковы их численные смысловые значения.

Для того чтобы локализовать определенный элемент массива, к его имени нужно добавить индекс. Так как мы моделируем массив, то должны позаботиться и о моделировании индекса. В языке ассемблера индексы массивов — это обычные адреса, но с ними работают особым образом. Другими словами, когда при программировании на ассемблере мы говорим об индексе, то скорее подразумеваем под этим не номер элемента в массиве, а некоторый адрес.

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

Пусть эта последовательность чисел трактуется как одномерный массив. Размерность каждого элемента определяется директивой dw , то есть она равна 2 байта. Чтобы получить доступ к третьему элементу, нужно к адресу массива прибавить 6 . Нумерация элементов массива в ассемблере начинается с нуля.

То есть в нашем случае речь, фактически, идет о 4 -м элементе массива — 3, но об этом знает только программист; микропроцессору в данном случае все равно — ему нужен только адрес.

В общем случае для получения адреса элемента в массиве необходимо начальный (базовый) адрес массива сложить с произведением индекса (номер элемента минус единица) этого элемента на размер элемента массива:

база + (индекс*размер элемента)

Архитектура микропроцессора предоставляет достаточно удобные программно-аппаратные средства для работы с массивами. К ним относятся базовые и индексные регистры, позволяющие реализовать несколько режимов адресации данных. Используя данные режимы адресации, можно организовать эффективную работу с массивами в памяти. Вспомним эти режимы:

  1. индексная адресация со смещением — режим адресации, при котором эффективный адрес формируется из двух компонентов:
  2. постоянного (базового) — указанием прямого адреса массива в виде имени идентификатора, обозначающего начало массива;
  3. переменного (индексного) — указанием имени индексного регистра.
  4. К примеру:

;поместить 3-й элемент массива mas в регистр ax:

  1. базовая индексная адресация со смещением — режим адресации, при котором эффективный адрес формируется максимум из трех компонентов:
  2. постоянного (необязательный компонент), в качестве которой может выступать прямой адрес массива в виде имени идентификатора, обозначающего начало массива, или непосредственное значение;
  3. переменного (базового) — указанием имени базового регистра;
  4. переменного (индексного) — указанием имени индексного регистра.

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

Напомним, что в качестве базового регистра может использоваться любой из восьми регистров общего назначения. В качестве индексного регистра также можно использовать любой регистр общего назначения, за исключением esp/sp.

Микропроцессор позволяет масштабировать индекс. Это означает, что если указать после имени индексного регистра знак умножения “*” с последующей цифрой 2, 4 или 8, то содержимое индексного регистра будет умножаться на 2, 4 или 8, то есть масштабироваться.

Применение масштабирования облегчает работу с массивами, которые имеют размер элементов, равный 2, 4 или 8 байт, так как микропроцессор сам производит коррекцию индекса для получения адреса очередного элемента массива. Нам нужно лишь загрузить в индексный регистр значение требуемого индекса (считая от 0). Кстати сказать, возможность масштабирования появилась в микропроцессорах Intel, начиная с модели i486. По этой причине в рассматриваемом здесь примере программы стоит директива .486 . Ее назначение, как и ранее использовавшейся директивы .386 , в том, чтобы указать ассемблеру при формировании машинных команд на необходимость учета и использования дополнительных возможностей системы команд новых моделей микропроцессоров.

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

Листинг 3. Просмотр массива слов с использованием

.data ;начало сегмента данных

mes1 db ‘не равен 0!$’,0ah,0dh

mes2 db ‘ равен 0!$’,0ah,0dh

mes3 db 0ah,0dh,’ Элемент $’

mas dw 2,7,0,0,1,9,3,6,0,8 ;исходный массив

.486 ;это обязательно

mov ds,ax ;связка ds с сегментом данных

xor ax,ax ; обнуление ax

mov cx,10 ;значение счетчика цикла в cx

mov esi,0 ; индекс в esi

mov dx,mas[esi*2] ;первый элемент массива в dx

cmp dx,0 ;сравнение dx c 0

je equal ;переход, если равно

not_equal: ;не равно

mov ah,09h ;вывод сообщения на экран

mov ah,02h ;вывод номера элемента массива на экран

inc esi ;на следующий элемент

dec cx ;условие для выхода из цикла

jcxz exit ;cx=0? Если да — на выход

jmp compare ;нет — повторить цикл

mov ah,09h ;вывод сообщения mes3 на экран

mov ah,09h ;вывод сообщения mes2 на экран

inc esi ;на следующий элемент

dec cx ;все элементы обработаны?

mov ax,4c00h ;стандартный выход

end main ;конец программы

Еще несколько слов о соглашениях:

;переслать байт из области данных, адрес

которой находится в регистре ebx:

  1. Если для задания адреса в команде используется прямая адресация (в виде идентификатора) в сочетании с одним регистром, то речь идет об индексной адресации. Регистр считается индексным, и поэтому можно использовать масштабирование для получения адреса нужного элемента массива:

;сложить содержимое eax с двойным словом в памяти

;по адресу mas + (ebx)*4

  1. Если для описания адреса используются два регистра, то речь идет о базово-индексной адресации. Левый регистр рассматривается как базовый, а правый — как индексный. В общем случае это не принципиально, но если мы используем масштабирование с одним из регистров, то он всегда является индексным. Но лучше придерживаться определенных соглашений.
  2. Помните, что применение регистров ebp/bp и esp/sp по умолчанию подразумевает, что сегментная составляющая адреса находится в регистре ss .

Заметим, что базово-индексную адресацию не возбраняется сочетать с прямой адресацией или указанием непосредственного значения. Адрес тогда будет формироваться как сумма всех компонентов.

;адрес операнда равен [mas+(ebx)+(ecx)*2]

;адрес операнда равен [(ebx)+8+(ecx)*4]

Но имейте в виду, что масштабирование эффективно лишь тогда, когда размерность элементов массива равна 2, 4 или 8 байт. Если же размерность элементов другая, то организовывать обращение к элементам массива нужно обычным способом, как описано ранее.

Рассмотрим пример работы с массивом из пяти трехбайтовых элементов (листинг 4). Младший байт в каждом из этих элементов представляет собой некий счетчик, а старшие два байта — что-то еще, для нас не имеющее никакого значения. Необходимо последовательно обработать элементы данного массива, увеличив значения счетчиков на единицу.

Листинг 4. Обработка массива элементов с нечетной длиной

MODEL small ; модель памяти

STACK 256 ;размер стека

.data ;начало сегмента данных

N=5 ;количество элементов массива

mas db 5 dup (3 dup (0))

.code ;сегмент кода

main: ;точка входа в программу

xor ax,ax ;обнуление ax

mov dl,mas[si] ;первый байт поля в dl

inc dl ;увеличение dl на 1 (по условию)

mov mas[si],dl ;заслать обратно в массив

add si,3 ;сдвиг на следующий элемент массива

Работа с одномерными массивами.

Методические указания к выполнению лабораторной работы

1) разобрать приведенные примеры;

2) внести изменения в предложенные исходные тексты:

— в примере 1 дописать необходимые команды,

— в примере 2 изменить программу так, чтобы ввод элементов массива осуществлялся с клавиатуры;

— в примере 3 изменить программу так, чтобы количество элементов массива и их значения вводились с клавиатуры;

3) в среде TASM создать исполняемые файлы и выполнить программы, реализующие примеры;

4) проверить правильность работы программ на тестах;

5) выполнить самостоятельное задание, предложенное преподавателем;

6) разработать систему тестов для верификации программы и провести тестирование.

Для самопроверки рекомендуется выполнить рассмотренные примеры, внеся необходимые изменения в тексты программ, а также одно из предложенных заданий.

Для контроля преподавателем необходимо выполнить рассмотренные примеры с необходимыми изменениями и выполнить задание преподавателя.

Следует продемонстрировать преподавателю работу приложения на разработанной системе тестов.

Необходимо подсчитать сумму элементов массива, состоящего из 10 однобайтовых элементов.

mas db size dup (?)

start : . . . ; ввод элементов массива

xor ax , ax ; в ax будем накапливать сумму

begin : add ax,[bx]

inc bx ;переход к следующему элементу (размер элемента=1 байту)

Необходимо подсчитать количество нулевых элементов массива.

Элементы массива являются однобайтовыми числами и заданы в сегменте данных.

len equ 10 ;количество элементов в mas

mas db 1,0,9,8,0,7,8,0,2,0

mov cx,len ; количество элементов в массиве в cx

xor si,si ; регистр si — индекс i , нумерация с 0

jcxz exit ;проверка cx на 0, если 0 (все элементы просмотрели), то на выход

cycl: cmp mas[si],0 ;сравнить очередной элемент mas с 0

jne m1 ; если не равно, то на m1

inc al ;если =0, то al +1, al — c четчик нулевых элементов

m1: i nc si ;перейти к следующему элементу i := i +1

exit : mov ax,4c00h

int 21h ;возврат управления операционной системе

Необходимо проверить, есть ли в массиве нулевые элементы

Элементы массива являются однобайтовыми числами и заданы в сегменте данных.

len equ 10 ;количество элементов в mas

mas db 1,0,9,8,0,7,8,0,2,0

message db 0 dh ,0 ah ,’В поле mas нет элементов, равных нулю ,$’

mov cx,len ; количество элементов массива=число повторений цикла

xor si,si ; индекс i , нумерация с нуля

jcxz exit ;проверка cx на 0, если 0, то на выход

mov si,-1 ;готовим si к адресации элементов поля mas

cmp mas[si],0 ;сравнить очередной элемент mas с 0

jz yes ;почему вышли из цикла?

mov ah,09 h ; вывод сообщения, если нет нулевых элементов

yes : ; есть нулевые элементы

int 21h ;возврат управления операционной системе

Задания

1. Задан одномерный массив двухбайтовых знаковых чисел.

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

2. Задан одномерный массив двухбайтовых знаковых чисел.

Необходимо разработать программу для подсчета суммы положительных элементов массива.

3. Задан одномерный массив однобайтовых чисел без знака.

Необходимо разработать программу для п оиска минимального (максимального) элемента массива.

4. Задан одномерный массив однобайтовых чисел без знака. Необходимо в ычислить среднее арифметическое ненулевых элементов массива. (Замечание. Нулевой элемент не должен суммироваться.)

Читать еще:  Единицей работы в системе си является
Ссылка на основную публикацию
Adblock
detector