Об индексах элементов массива




Мы уже знаем, что в ЯА массивы описываются по директивам определения данных с использованием конструкции повторения DUP. Однако кое-что здесь требует уточнения.

Пусть имеется массив X из 30 элементов-слов:

X DW 30 DUP(?)

Как видно, при описании массива указывается количество элементов в нем и их тип, но не указывается, как нумеруются (индексируются) его элементы. Поэтому такому описанию может соответствовать и массив, в котором элементы нумеруются с 0, т. е. Х[0..29], и массив, в котором нумерация начинается с 1, т. е. Х[1..30], и массив с любым другим начальным индексом к, т. е. X[k..29+k]. Таким образом, автор программы может "накладывать" на массив различные диапазоны изменения индекса. Какой диапазон выбрать? Иногда границы изменения индекса могут жестко определяться условиями задачи (например, в задаче явно сказано, что элементы нумеруются с 1). Но если нумерация не навязывается извне, тогда лучше выбрать нумерацию с 0. Почему?

Чтобы ответить на этот вопрос, рассмотрим, как зависит адрес элемента массива от индекса этого элемента. Пусть мы решили, что элементы массива X нумеруются с к:

X DB 30 DUP(?);X[k..29+k]

Тогда верно следующее соотношение:

адрес(Х[1]) = X+2*(i-k)

или в более общем виде, где явный размер (2) элементов массива завуалирован:

адрес (Х[±]) = X+(type X)*(i-k)

Эта зависимость становится наиболее простой при k=0:

адрес(Х[1]) = X+(type X)*i

Поэтому обычно и считают при программировании на ЯА, что элементы массива нумеруются с 0:

X DW 30 DUP(?);X[0..29]

В дальнейшем именно так мы и будем делать.

Для многомерных массивов ситуация аналогична. Пусть, к примеру, имеется двумерный массив (матрица) А, в котором N строк и М столбцов (N и М - константы) и все элементы - двойные слова, причем строки нумеруются с kl, а столбцы - с k2:

A DD N DUP(M DDP(?)); A[kl..N+(k-1),k2..M+(k2-l)]

Здесь мы предполагаем, что элементы матрицы размещаются в памяти по строкам: первые М ячеек (двойных слов) занимают элементы первой строки матрицы, следующие М ячеек - элементы второй строки и т. д. Конечно, элементы матрицы можно размещать и по столбцам, но традиционно принято построчное размещение; его мы и будем придерживаться.

При этом предположении зависимость адреса элемента матрицы от индексов элемента выглядит так:

адрес(A[i,j])-A+M*(type A)*(i-kl)+(type A)*(j-k2)

И здесь наиболее простой вид эта зависимость приобретает при нумерации с О, при kl=0 и k2=0:

адрес(A[i,j])= A+M*(type A)*i+(type A)*j

 

Реализация переменных с индексом

Следующий вопрос, который возникает при работе с массивами, - это как осуществляется доступ к их элементам, как реализуются переменные с индексом. Чтобы ответить на этот вопрос, надо предварительно познакомиться с такой особенностью ЭВМ, как модификация адресов.

Модификация адресов

До сих пор мы рассматривали команды, в которых для операндов из памяти указывались их точные адреса (имена), например: MOV СХ,А. Однако в общем случае в команде вместе с адресом может быть указан в квадратных скобках не который регистр, например: MOV СХ,А[ВХ]. Тогда команда будет работат! не с указанным в ней адресом А, а с так называемым исполнительным (другое назва ние - эффективным) адресом Аисп, который вычисляется по следующей формуле:

Аисп =(А + [ВХ]) mod 216,

где [ВХ] обозначает содержимое регистра ВХ. Другими словами, прежде чeм выполнить команду, центральный процессор прибавит к адресу А, указанном1 в команде, текущее содержимое регистра ВХ, получит некоторый новый адре и именно из ячейки с этим адресом возьмет второй операнд. (Сама команда npi этом не меняется, суммирование происходит внутри центрального процессора. Если в результате сложения получилась слишком большая сумма, то от нее берутся только последние 16 битов, на что и указывает операция mod в приведенной формуле. (Отметим, что если в команде рядом с адресом не указан регистр, то исполнительный адрес считается равным адресу из команды.)

Замена адреса из команды на исполнительный адрес называется модификацией адреса, а регистр, участвующий в модификации, принято называть регистром-модификатором или просто модификатором. Отметим при этом, что в ПК в качестве модификатора можно использовать не любой регистр, а только один из следующих четырех: ВХ, ВР, SI или DI.

Возьмем, к примеру, команду ADD A[SI],5. Здесь в роли модификатора выступает регистр SI. Пусть сейчас в нем находится число 100. Тогда Аисп=А+[81]=А+100. Значит, по данной команде число 5 будет прибавлено к числу из ячейки с адресом А+100, а не из ячейки с адресом А. Если же в SI находится величина -2 (OFFFEh), тогда Аисп=А-2 и потому число 5 будет складываться с числом из ячейки с адресом А-2.

Этот пример показывает, что одна и та же команда может работать с разными адресами. Это очень важно, ради этого и вводится модификация адресов. Одним из случаев, где полезна модификация адресов, является индексирование, используемое для реализации переменных с индексом.

Индексирование

Рассмотрим следующий пример: пусть имеется массив

X DW 100 DUP(?);X[0..99]

и требуется записать в регистр АХ сумму его элементов.

Для нахождения суммы надо сначала в АХ записать 0, а затем в цикле выполнять операцию AX:=AX+X[i] при i от 0 до 99. Поскольку адрес элемента X[i] равен X+2*i, то команда, соответствующая этой операции, должна быть следующей:

ADD AX,X+2*i

Но такая команда запрещена правилами и машинного языка, и ЯА: в любой команде все ее части, в том числе и адрес, должны быть фиксированными, не должны меняться. У нас же адрес меняется вместе с изменением индекса i.

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

Разобьем переменный адрес X+2*i на два слагаемых - на постоянное слагаемое X, которое не зависит от индекса i, и на переменное слагаемое 2*1, зависящее от индекса. Постоянное слагаемое записываем в саму команду, а переменное слагаемое заносим в какой-нибудь регистр-модификатор (скажем, в SI) и название этого регистра также записываем в команду в качестве модификатора:

Что получилось? Поскольку регистр-модификатор один и тот же, то такая команда имеет фиксированный вид, т. е. удовлетворяет правилам машинного языка. С другой стороны, команда работает с исполнительным адресом, а он получается сложением адреса X из команды с содержимым (2*1) регистра SI, которое может меняться. Поэтому, меняя значение SI, мы заставим неменяющуюся команду работать с разными адресами. Тем самым удовлетворяются требования как машинного языка, так и алгоритма. Единственное, что осталось сделать, - это правильно менять содержимое регистра SI. Но это уже делается просто: вначале в SI надо заслать 0, а затем увеличивать его значение с шагом 2; в результате наша команда будет работать с адресами X, Х+2, Х+4,..., Х+198.

Поскольку в данном случае регистр-модификатор используется для хранения индекса (точнее - выражения, зависящего от индекса), то такой регистр называют индексным регистром, а описанный способ получения адреса переменной с индексом - индексированием.

С учетом всего сказанного фрагмент программы нахождения суммы элементов массива X выглядит так:

Косвенные ссылки

Рассмотрим еще один случай применения модификации адресов.

Пусть нам надо решить следующую задачу: имеется некоторая ячейка размером в слово, адрес которой нам не известен, но известно, что этот адрес находите в регистре ВХ, и надо записать, скажем, число 300 в эту ячейку:

Если бы мы заранее знали адрес (х) этой ячейки, то наша задача решалась командой MOV х,300. Но в момент составления программы мы не знаем этот адрес, а потому и не можем указать его в команде. Что делать? Вспомним, что команда работают с исполнительными адресами, поэтому нам надо взять такой адрес и такой модификатор, чтобы в сумме они давали этот заранее не известный нам адрес Легко сообразить, что в нашем случае надо взять нулевой адрес и регистр поскольку тогда Аисп=0+[ВХ]=0+х=х. Поэтому наша задача решается командой

MOV [ВХ],300

Особенность используемого здесь способа модификации адреса заключаете в том, что мы, как и прежде, представляем адрес в виде суммы двух слагаемых, одно из которых записываем в команду, а другое - в регистр, но если ранее у нас оба слагаемых были ненулевыми, то теперь одно слагаемое, которое мы помещаем в команду, нулевое и потому весь адрес "упрятан" в регистре. Получается, что в команде мы указывается лишь место (регистр), где находится адрес. Такой способ задания адреса через промежуточное звено называют косвенной ссылкой или косвенной адресацией.

Отметим попутно, что при косвенной ссылке обычно приходится уточнять размер ячейки, на которую она указывает. Если, к примеру, в ячейку, адрес которой находится в регистре ВХ, надо записать число 0, тогда использовать для этого команду MOV [ВХ],0 нельзя, т. к. в ней непонятны размеры операндов: 0 может быть как байтом, так и словом, да и адрес из ВХ также может быть адресом как байта, так и слова (в приведенном выше примере такой неоднозначности не было, т. к. число 300 может быть только словом). Поэтому с помощью оператора PTR надо указать, операнды какого размера мы имеем в виду:

Литература:

1. Пильщиков В.Н. Программирование на языке ассемблера IBM РС. – М.: «Диалог - МИФИ», 1999 – 288с.

2. Использование Turbo Assembler при разработке программ. – Киев: «Диалектика», 1994. – 288с.

 

 

Лекция 15.

Тема: Понятие о массивах. Работа с двумерным массивом.

Содержание: Модификация по нескольким регистрам. Запись модифицируемых адресов в ЯА.

Краткое содержание лекции:



Поделиться:




Поиск по сайту

©2015-2024 poisk-ru.ru
Все права принадлежать их авторам. Данный сайт не претендует на авторства, а предоставляет бесплатное использование.
Дата создания страницы: 2016-02-16 Нарушение авторских прав и Нарушение персональных данных


Поиск по сайту: