При описании записи для каждого элемента указывается его длина в битах и, что необязательно, некоторое значение.
Суммарный размер записи определяется суммой размеров ее полей и не может быть более 8, 16 или 32 бит.
Если суммарный размер записи меньше указанных значений, то все поля записи “прижимаются” к младшим разрядам.
В отличие от структур, дающих имена байтам, словам, двойным словам или целым массивам, в записях определяются строки битов внутри байтов, слов или двойных слов.
Использование записей в программе, так же, как и структур, организуется в три этапа:
- Задание шаблона записи, то есть определение набора битовых полей, их длин и, при необходимости, инициализация полей.
- Определение экземпляра записи. Так же, как и для структур, этот этап подразумевает инициализацию конкретной переменной типом заранее определенной с помощью шаблона записи.
- Организация обращения к элементам записи.
Описание записи
Описание шаблона записи имеет следующий синтаксис:
имя_записи RECORD <описание элементов>
Здесь:
<описание элементов> представляет собой последовательность описаний отдельных элементов записи согласно синтаксической диаграмме (см. рис.):
При описании шаблона память не выделяется, так как это всего лишь информация для транслятора ассемблера о структуре записи.
Пример:
iotest record i1:1,i2:2=11,i3:1,i4:2=11,i5:2=00
Так же, как и для структур, местоположение шаблона в программе может быть любым, но при этом необходимо учитывать логику работы однопроходного транслятора.
Определение экземпляра записи
Для использования шаблона записи в программе необходимо определить переменную с типом данной записи, для чего применяется следующая синтаксическая конструкция (см. рис.):
Анализируя эту синтаксическую диаграмму, можно сделать вывод, что инициализация элементов записи осуществляется достаточно гибко. Рассмотрим несколько вариантов инициализации.
Если инициализировать поля не требуется, то достаточно указать ? при определении экземпляра записи:
flag iotest ?
Если вы составите и исследуете в отладчике тестовый пример с данным определением записи, то увидите, что все поля переменной типа запись flag обнуляются. Это происходит несмотря на то, что в определении записи заданы начальные значения полей.
Если требуется частичная инициализация элементов, то они заключаются в угловые (< и >) или фигурные ({ и }) скобки.
Различие здесь в том, что в угловых скобках элементы должны быть заданы в том же порядке, что и в определении записи. Если значение некоторого элемента совпадает с начальным, то его можно не указывать, но обязательно обозначить его запятой. Для последних элементов идущие подряд запятые можно опустить.
К примеру, согласиться со значениями по умолчанию можно так:
flag iotest <> ;согласились со значением по умолчанию
Изменить значение поля i2 можно так:
flag iotest <,10,> ; переопределили i2
Применяя фигурные скобки, также можно указать выборочную инициализацию полей, но при этом необязательно обозначать запятыми поля, со значениями по умолчанию которых мы согласны:
flag iotest {i2=10} ;переопределили i2,
;не обращая внимания на порядок
;следования других компонентов записи
Работа с записями
Как организовать работу с отдельными элементами записи? Обычные механизмы адресации здесь бессильны, так как они работают на уровне ячеек памяти, то есть байтов, а не отдельных битов. Здесь программисту нужно приложить некоторые усилия.
Прежде всего для понимания проблемы нужно усвоить несколько моментов:
- Каждому имени элемента записи ассемблер присваивает числовое значение, равное количеству сдвигов вправо, которые нужно произвести для того, чтобы этот элемент оказался “прижатым” к началу ячейки. Это дает нам возможность локализовать его и работать с ним. Но для этого нужно знать длину элемента в битах.
mov ah,i2 ;получаем количество сдвигов в право - Сдвиг вправо производится с помощью команды сдвига shr.
- Ассемблер содержит оператор width, который позволяет узнать размер элемента записи в битах или полностью размер записи. Варианты применения оператора width:
width имя_элемента_записи ;значением оператора
;будет размер элемента в битах
width имя_экземпляра_записи
или
width имя_типа_записи ;значением оператора
;будет размер всей записи в битах.
mov al,width i2
...
mov ax,width iotest - Ассемблер содержит оператор mask, который позволяет локализовать биты нужного элемента записи. Эта локализация производится путем создания маски, размер которой совпадает с размером записи. В этой маске обнулены биты на всех позициях, за исключением тех, которые занимает элемент в записи.
- Сами действия по преобразованию элементов записи производятся с помощью логических команд.
Выделение элемента записи:
- Поместить запись во временную память — регистр (8, 16 или 32-битный в зависимости от размера записи).
- Получить битовую маску, соответствующую элементу записи, с помощью оператора mask.
- Локализовать биты в регистре с помощью маски и команды and.
- Сдвинуть биты элемента к младшим разрядам регистра командой shr. Число разрядов для сдвига получить с использованием имени элемента записи.
Работа с элементом записи:
Как мы уже выяснили, с элементами записи производятся любые действия, как над обычной двоичной информацией.
Единственное, что нужно отслеживать, — это размер битового поля. Если, к примеру, размер поля увеличится, то впоследствии может произойти случайное изменение соседних полей битов. Поэтому желательно исключить изменение размера поля.
Помещение измененного элемента на его место в запись:
- Используя имя элемента записи в качестве счетчика сдвигов, сдвинуть влево биты элемента записи (команда shl).
- Если вы не уверены в том, что разрядность результата преобразований не превысила исходную, можно выполнить “обрезание” лишних битов, используя команду and и маску элемента.
- Подготовить исходную запись к вставке измененного элемента путем обнуления битов в записи на месте этого элемента. Это можно сделать путем наложения командой and инвертированной маски элемента записи на исходную запись.
- С помощью команды or наложить значение в регистре на исходную запись.
Програмулина ни чего не выводит на экран, так как предназначена для медитации на нее под отладчиком. В программе создается экземпляр записи iotest с именем flag, имеющий двоичное значение (по умолчанию) - 10001100 (8Сh). Программа устанавливает третий слева бит (младший бит i2) в единичку. Соответственно, после этих изменений, в переменной flag должно быть значение ACh (10101100).
Теперь листинг программы...
И немного отладчика...
Этот скрин сделан после выполнения первых двух команд программы. Следующий уже после выполнения команды or.
Комментариев нет:
Отправить комментарий