|
Структура данных - это организация данных,
которая имеет для
программиста определенный смысл. Как
показывает опыт, мы определяем
структуры данных когда одна и та же
совокупность данных
используется более чем одной программой
или программистами.
Благодаря определению, обе стороны имеют
четкий образ этих данных.
Если программа A передает некотрые данные
программе B, то
определение структуры данных гарантирует,
что каждая из программ
ищет данные в одном и том же месте.
У нас уже был хороший пример структуры
данных. Блок управления
файлом FCB является структурой данных.
Блок FCB используется
программами для обмена информацией о файле
с DOS. В блоке FCB
содержатся такие важные данные об
обрабатываемом файле, как номер
текущей записи, длина файла и т.д. Кроме
того, в блоке FCB имеется
зарезервированное поле, которое содержит
информацию, используемую
только DOS. В блоке FCB находится вся
информация, необходимая для
DOS и прикладных программ. Эта структура
данных служит для передачи
параметров файла между DOS и прикладной
программой.
Теперь нужно найти такой способ
определения структур данных,
чтобы программа могла с удобством ими
пользоваться. В
Макроассемблере фирмы IBM имеется оператор
STRUC, позволяющий
определять структуру данных. С точки
зрения программиста структура
данных выглядит как еще один сегмент.
Определение данных
ассемблируется так же, как и обычные
операторы данных, и описание
структуры, как и описание сегмента,
заканчивается оператором ENDS.
Однако в действительности структура не
генерирует данные. Оператор
STRUC определяет структуру данных для
ассемблера. В дальнейшем имя
этой структуры данных используется в
ассемблируемой программе для
генерации соответствующей области данных.
Если рассматривать оператор STRUC
описанным выше образом, то он
больше похож на оператор MACRO. Программа
определяет структуру
данных в одном месте, а ее вызов
осуществляет позднее. Фактическая
генерация данных происходит при вызове
структуры. Фиг. 6.14 поможет
понять работу оператора STRUC.
Microsoft (R) Macro Assembler Version 5.00 1/1/80 04:03:36
Фиг. 6.14 Структуры
Page1-1
PAGE,132
TITLEФиг. 6.14 Структуры
FCBSTRUC
000000DRIVEDB0; Номер устройства
000120 20 20 20 20 20 20FILE_NAMEDB''; Имя файла
20
000920 20 20FILE_EXTDB''; Тип файла
000C0000CURRENT_BLOCKDW0; Номер текущего блока
000E0080RECORD_SIZEDW80H; Логический размер записи
001000000000FILE_SIZEDD0; Размер файла в байтах
00140000DATE DW0; Дата последнего изменения
Фиг. 6.14 Структуры (начало)
0016000A[RESERVEDDB10 DUP (?); Зарезервировано
ДОС
??
]
002000SEQ_NUMBERDB0; Номер текущей записи
002100000000RANDOM_NUMBERDD0; Номер записи при прямом
;доступе
0025FCBENDS
0000STACKSEGMENT STACK
00000040[DW64DUP (?)
????
]
0080STACKENDS
0000CODESEGMENT
ASSUMECS:CODE
000001INPUTFCB<1,'FIG6-14','INP'>
0001464947362D313420
0009494E50
000C0000
000E0080
001000000000
00140000
0016000A[
??
]
002000
002100000000
002502OUTPUTFCB<2,'EXAMPLE','TST'>
00264558414D504C4520
002E545354
00310000
00330080
003500000000
00390000
003B000A[
??
]
004500
004600000000
004ASTRUCTURESPROCFAR
004A1EPUSHDS ; Установка адреса возврата
004BB8 0000MOVAX,0
004E50PUSHAX
004F0EPUSHCS ; Установка DS на сегмент CODE
00501FPOPDS
ASSUMEDS:CODE
00518D 16 0000 RLEADX,INPUT; Открытие вводимого файл
Фиг. 6.14 Структуры (продолжение)
0055B4 0FMOVAH,0FH
0057CD 21INT21H
00598D 16 0025 RLEADX,OUTPUT; Создание выводимого файла
005DB4 16MOVAH,16H
005FCD 21INT21H
00618D 1E 0000 RLEABX,INPUT
0065C7 47 0E 0010MOV[BX].RECORD_SIZE,16; Установка размера записи для ввода
006AC6 47 20 01 MOV[BX].SEQ_NUMBER,1; Пропуск первой записи
006EC7 06 0033 R 0010MOVOUTPUT.RECORD_SIZE,16;
Установка размера записи для
;вывода
00748D 16 0000 RLEADX,INPUT; Чтение второй записи из файла
0078B4 14MOVAH,14H
007ACD 21INT21H
007C8D 16 0025 RLEADX,OUTPUT; Вывод введенной записи
0080B4 15MOVAH,15H
0082CD 21INT21H
0084B4 10MOVAH,10H; Закрытие выводимого файла
0086CD 21INT21H
0088CBRET
0089STRUCTURESENDP
0089CODEENDS
END
Microsoft (R) Macro AssemblerVersion 4.004/16/89 23:15:19
Фиг. 6.14 СтруктурыSymbols-1
Structures and Records:
N a m eWidth# fields
ShiftWidthMaskInitial
FCB. . . . . . . . . . . . . .0025000A
DRIVE. . . . . . . . . . . .0000
FILE_NAME. . . . . . . . . .0001
FILE_EXT . . . . . . . . . . .0009
CURRENT_BLOCK. . . . . . . .000C
RECORD_SIZE. . . . . . . . .000E
FILE_SIZE. . . . . . . . . .0010
DATE . . . . . . . . . . . . .0014
RESERVED . . . . . . . . . . .0016
SEQ_NUMBER . . . . . . . . . .0020
RANDOM_NUMBER. . . . . . . .0021
Фиг. 6.14 Структуры (продолжение)
На Фиг. 6.14 приведена очень простая
программа, которая
использует файлы системы DOS. Эта
программа открывает файл DOS на
носителе в дисководе A:, считывает вторую
запись этого файла и
записывает ее в файл на носителе в
дисководе B:. Маловероятно,
чтобы вы когда-нибудь применили эту
программу чтобы сделать
что-либо существенное, но сейчас она дает
нам возможность
использовать структуру данных для блока
FCB.
Первая часть программы на Фиг. 6.14
определяет структуру данных
FCB. Оператор языка ассемблера STRUC
отмечает начало определения
структуры. Метка FCB является здесь именем
данной конкретной
структуры. В примере определяется каждое
поле структуры данных FCB.
Обратите внимание, что в столбцах слева
ассемблер генерирует
объектный код данной структуры. Однако,
при редактировании связей
ассемблированного объектного кода, область
данных в программе
отсутствует. Ассемблер распечаьываеь
данную структуру данных в
оттранслированном виде исключительно для
вашего сведения.
Точно так же, как и вслучае макрокоманды,
имя FCB становится
как бы новым оператором языка ассемблера.
Первым оператором в
сегменте CODE является вызов структуры
данных FCB. В примере этой
структуре данных присваивается имя INPUT.
Данная структура FCB
идентифицирует входной набор данных.
Заметьте, что в этом операторе
FCB имеются операнды. Они заменяют или
перекрывают значения,
которые были включены в исходное
определение структуры данных.
Если мы сравним объектный код определения
структуры FCB с
объектным кодом структуры INPUT, то
увидим, что они различаются по
значениям первых трех полей. В определении
структуры данных поле
DRIVE равно 0, в структуре INPUT - 1.
Первый операнд в угловых
скобках определения структуры INPUT равен
1. Это значение заменяет
исходно определенное значение 0.
Аналогично в данном примере
изменяются значения второго и третьего
полей, относящихся к имени
файла. Закрывающая угловая скобка в
определении структуры INPUT
завершает процедуру замены значений полей
структуры данных.
Оставшаяся часть структуры INPUT идентична
определеной в структуре
данных FCB.
Программа может изменять любой из полей
структуры FCB, если
определение этого поля содержит только
один элемент. В
рассматриваемом примере программа может
изменять любое поле
структруыр FCB, за исключением поля
RESERVED. Мы определили это
поле поле как 10 отдельных элементов, и
оно не может быть изменено.
Аналогично, если поле определено
оператором
DB 10,20
то его нельзя перекрыть. При вызове
структуры можно изменять только
поля, состоящие из единственного элемента.
Символьная строка,
включающая несколько символов,
рассматривается ассемблером как один
элемент. В данном примере поле FILE_NAME
содержит несколько
символов, но является одним элементом,
значение которого можно
изменить.
Операнды, перечисленные в угловых скобках,
заменяют операнды,
входящие в определение, по позиционному
принципу, как и в
макрокоманде. Если вы не хотите
модифицировать заданное в
определении значение, но желаете изменить
следующее за ним поле, то
в список значений нужно включить пустой
параметр. Например, для
модификации полей FILE_NAME и
CURRENT_BLOCK, оставляя в то же время
по умолчанию заданные значения полей DRIVE
и FILE_EXT, структуру
FCB следует вызвать оператором:
EXAMPLE FCB <,NEWNAME,,12>
Первый параметр пуст, так что ассемблер
использует для него
значение по умолчанию. В следующем поле
NEWNAME заменяет строку
пробелов. Для значения поля FILE_EXT по
умолчанию используется
строка пробелов, и наконец, нулевое
значение поля CURRENT_BLOCK
заменяется на 12.
В следующей исходной программной строке на
Фиг. 6.14 программа
определяет структуру FCB под именем OUTPUT
для выходного файла.
Здесь снова модифицируются первые три поля
определения данных путем
включения новых значений в поля операндов
оператора FCB.
Выигрыш от использования структур данных
проявляется в
действительных командах программы.
Программа может ссылаться на
имена INPUT и OUTPUT так же, как и на
любые другие метки в
программе. Вы можете видеть это, в том
участке программы, где
открывается входной файл INPUT и оператор
LEA DX,INPUT
используется дляустановки адреса входной структуры данных FCB.
В программе можно использовать каждое из
указанных полей
структуры данных. Значению каждого имени
соответствует смещение
какого-либо поля в структуре данных.
Например, программа помещает в
регистр BX адрес FCB INPUT. После этого
программа обращается к
полям RECORD_SIZE и SEQ_NUMBER в режиме
адресации по базе. Так как
регистр BX уже указывает на структуру
данных FCB, то нужно задать
смещение относительно этой базы. Способ
адресации
[BX].RECORD_SIZ
указывает ассемблеру, что в команде,
которую он должен
сгенерировать, смещение поля RECORD_SIZE
складывается со значением
базы, хранящимся в регистре BX. Если вы
рассмотрите соответствующие
команды на машинном языке, то увидите, что
в них присутствуют
смещения для полей RECORD_SIZE (0EH) и
SEQ_NUMBER (20H). Символ "."
идентифицирует имена полей как смещения в
структуре данных.
Помимо режимов адресации по базе и индексу
можно использовать
структуру данных и для прямой адресации.
Следующий участок
программы непосредственно изменяет поле
RECORD_SIZE в FCB OUTPUT.
Программа именует это поле
OUTPUT.RECORD_SIZE. Имя OUTPUT
определяет конкретную структуру данных, а
RECORD_SIZE - имя поля в
этой структуре данных.
Прежде, чем покончить с этим примером,
посмотрим, какой
информацией о структуре данных располагает
ассемблер. Фиг. 6.14
включает в себя фрагмент таблицы
символических имен. Ассемблер
выделяет один из разделов этой таблицы для
структур и записей.
Ассемблер показывает вам всю информацию о
структуре данных, которой
располагает. Этот раздел имеет заголовок
"Structures and records"
("Структуры и записи"). В первой
строке этого раздела для структуры
FCB из нашего примера указано, что эта
структура имеет длину 25H
байт и содержит 0AH полей. Далее ассемблер
перечисляет все эти
поля, печатая их с отступом по отношению к
имени структуры. Для
каждого из полей приводится значение
соответствующего смещения. Для
структур ассемблер использует два столбца,
обозначеные "width"
(ширина) и "#dfields" (число
полей). Вторая строка в меток колонок
используется для записей. Структуры
данных, которые ассемблер
интерпретирует как записи, будут
рассмотрены в следующем разделе.
Программа, приведенная на Фиг. 6.14, не
делает ничего
полезного. Кроме того, в ней нет никакой
обработки ошибок. Однако
она хорошо иллюстрирует применение
оператора STRUC. Этот способ
определения данных особенно подходит для
часто используемых
структур данных. Использование имен полей
в качестве значений
смещений очень удобно при модификации
структур данных на этапе
разработки программы. Если вы внесете
изменения в структуру данных,
то ассемблер автоматически изменит
значения смещений при повторном
ассемблировании программы. Кроме того,
использование структур
данных делает программу на языке
ассемблера более читабельной и
понятной.
|