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



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

  1. Перечислением элементов массива в поле операндов одной из директив описания данных. При перечислении элементы разделяются запятыми. К примеру:
          ;массив из 5 элементов.Размер каждого элемента 4 байта:mas dd 1,2,3,4,5
  1. Используя оператор повторения dup. К примеру:
 ;массив из 5 нулевых элементов.;Размер каждого элемента 2 байта:mas    dw     5 dup (0)

 

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

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

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

  1. Использование цикла для инициализации значениями области памяти, которую можно будет впоследствии трактовать как массив.
  2. Посмотрим на примере листинга 2, каким образом это делается.
  Листинг 2 Инициализация массива в цикле;prg_12_1.asmMASMMODEL smallSTACK 256.datames    db      0ah,0dh,'Массив- ','$'mas    db      10 dup (?) ;исходный массивi         db      0.codemain:          mov   ax,@data          mov   ds,ax          xor     ax,ax  ;обнуление ax          mov   cx,10  ;значение счетчика цикла в cx          mov   si,0     ;индекс начального элемента в cxgo:                                                   ;цикл инициализации          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      21hshow:          mov   ah,02h ;функция вывода значения из al на экран          mov   dl,mas[si]          add    dl,30h ;преобразование числа в символ          int      21h          inc      si          loop   showexit:          mov   ax,4c00h ;стандартный выход          int      21hend    main                  ;конец программы

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

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

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

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

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

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

mas    dw     0,1,2,3,4,5

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

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

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

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

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

  • индексная адресация со смещением — режим адресации, при котором эффективный адрес формируется из двух компонентов:
    • постоянного (базового) — указанием прямого адреса массива в виде имени идентификатора, обозначающего начало массива;
    • переменного (индексного) — указанием имени индексного регистра.
    • К примеру:
mas    dw     0,1,2,3,4,5...          mov   si,4;поместить 3-й элемент массива mas в регистр ax:          mov   ax,mas[si]
  • базовая индексная адресация со смещением — режим адресации, при котором эффективный адрес формируется максимум из трех компонентов:
    • постоянного (необязательный компонент), в качестве которой может выступать прямой адрес массива в виде имени идентификатора, обозначающего начало массива, или непосредственное значение;
    • переменного (базового) — указанием имени базового регистра;
    • переменного (индексного) — указанием имени индексного регистра.

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

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

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

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

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

 Листинг 3. Просмотр массива слов с использованиеммасштабирования;prg_12_2.asmMASMMODEL smallSTACK 256.data  ;начало сегмента данных;тексты сообщений:mes1  db      'не равен 0!$',0ah,0dhmes2  db      'равен 0!$',0ah,0dhmes3  db      0ah,0dh,'Элемент $'mas    dw     2,7,0,0,1,9,3,6,0,8 ;исходный массив.code.486                   ;это обязательноmain:          mov   ax,@data          mov   ds,ax  ;связка ds с сегментом данных          xor     ax,ax  ;обнуление axprepare:          mov   cx,10  ;значение счетчика цикла в cx          mov   esi,0   ;индекс в esicompare:          mov   dx,mas[esi*2]   ;первый элемент массива в dx          cmp    dx,0   ;сравнение dx c 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     cx                      ;условие для выхода из цикла          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     cx                      ;все элементы обработаны?          jcxz    exit          jmp    compareexit:          mov   ax,4c00h ;стандартный выход          int      21hend    main   ;конец программы

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

  • Если для описания адреса используется только один регистр, то речь идет о базовой адресации и этот регистр рассматривается как базовый:
;переслать байт из области данных, адрескоторой находится в регистре ebx: mov al,[ebx]
  • Если для задания адреса в команде используется прямая адресация (в виде идентификатора) в сочетании с одним регистром, то речь идет об индексной адресации. Регистр считается индексным, и поэтому можно использовать масштабирование для получения адреса нужного элемента массива:
 add eax,mas[ebx*4];сложить содержимое eax с двойным словом в памяти;по адресу mas + (ebx)*4
  • Если для описания адреса используются два регистра, то речь идет о базово-индексной адресации. Левый регистр рассматривается как базовый, а правый — как индексный. В общем случае это не принципиально, но если мы используем масштабирование с одним из регистров, то он всегда является индексным. Но лучше придерживаться определенных соглашений.
  • Помните, что применение регистров ebp/bp и esp/sp по умолчанию подразумевает, что сегментная составляющая адреса находится в регистре ss.

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

К примеру:

          mov   ax,mas[ebx][ecx*2];адрес операнда равен [mas+(ebx)+(ecx)*2]...          sub     dx,[ebx+8][ecx*4];адрес операнда равен [(ebx)+8+(ecx)*4]

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

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


Дата добавления: 2019-09-13; просмотров: 226; Мы поможем в написании вашей работы!

Поделиться с друзьями:






Мы поможем в написании ваших работ!