Структуры



Структуры


    Структура данных - это организация данных, которая имеет для
    программиста определенный смысл. Как показывает опыт, мы определяем
    структуры данных когда одна и та же совокупность данных
    используется более чем одной программой или программистами.
    Благодаря определению, обе стороны имеют четкий образ этих данных.
    Если программа 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 Структуры                              Page   1-1
 
                                         PAGE    ,132
                                         TITLE   Фиг. 6.14 Структуры
 
                                   FCB     STRUC
            0000  00                     DRIVE       DB      0               ; Номер устройства
            0001  20 20 20 20 20 20 20     FILE_NAME       DB      '        '      ; Имя файла
                20
            0009  20 20 20               FILE_EXT          DB      '   '           ; Тип файла
            000C  0000             CURRENT_BLOCK   DW      0                 ; Номер текущего блока
            000E  0080             RECORD_SIZE     DW      80H         ; Логический размер записи
            0010  00000000               FILE_SIZE         DD      0               ; Размер файла в байтах
            0014  0000             DATE       DW      0               ; Дата последнего изменения
 
                     Фиг. 6.14 Структуры (начало)
            0016  000A[            RESERVED          DB      10 DUP (?)      ; Зарезервировано ДОС
                   ??
                              ]
            0020  00                     SEQ_NUMBER      DB      0                 ; Номер текущей записи
            0021  00000000               RANDOM_NUMBER   DD      0                 ; Номер записи при прямом
                                                                 ;      доступе
            0025                   FCB     ENDS
 
            0000                   STACK   SEGMENT STACK
            0000  0040[                  DW      64      DUP (?)
                  ????
                              ]
            0080                   STACK   ENDS
 
            0000                   CODE    SEGMENT
                                         ASSUME  CS:CODE
 
            0000  01                     INPUT   FCB     <1,'FIG6-14','INP'>
            0001  464947362D313420
            0009  494E50
            000C  0000
            000E  0080
            0010  00000000
            0014  0000
            0016  000A[
                   ??
                              ]
            0020  00
            0021  00000000
 
            0025  02                     OUTPUT  FCB     <2,'EXAMPLE','TST'>
            0026  4558414D504C4520
            002E  545354
            0031  0000
            0033  0080
            0035  00000000
            0039  0000
            003B  000A[
                   ??
                              ]
            0045  00
            0046  00000000
 
 
            004A                   STRUCTURES      PROC    FAR
            004A  1E                           PUSH    DS              ; Установка адреса возврата
            004B  B8 0000                      MOV     AX,0
            004E  50                           PUSH    AX
            004F  0E                           PUSH    CS              ; Установка DS на сегмент CODE
            0050  1F                           POP     DS
                                         ASSUME  DS:CODE
            0051  8D 16 0000 R                 LEA     DX,INPUT             ; Открытие вводимого файл
 
                 Фиг. 6.14 Структуры (продолжение)
            0055  B4 0F                  MOV     AH,0FH
            0057  CD 21                  INT     21H
 
            0059  8D 16 0025 R                 LEA     DX,OUTPUT            ; Создание выводимого файла
            005D  B4 16                  MOV     AH,16H
            005F  CD 21                  INT     21H
 
            0061  8D 1E 0000 R                 LEA     BX,INPUT
            0065  C7 47 0E 0010                MOV     [BX].RECORD_SIZE,16    ; Установка размера записи для ввода
            006A  C6 47 20 01                  MOV     [BX].SEQ_NUMBER,1          ; Пропуск первой записи
 
            006E  C7 06 0033 R 0010            MOV     OUTPUT.RECORD_SIZE,16  ; Установка размера записи для
                                                                 ;      вывода
            0074  8D 16 0000 R                 LEA     DX,INPUT             ; Чтение второй записи из файла
            0078  B4 14                  MOV     AH,14H
            007A  CD 21                  INT     21H
 
            007C  8D 16 0025 R                 LEA     DX,OUTPUT            ; Вывод введенной записи
            0080  B4 15                  MOV     AH,15H
            0082  CD 21                  INT     21H
 
            0084  B4 10                  MOV     AH,10H               ; Закрытие выводимого файла
            0086  CD 21                  INT     21H
 
            0088  CB                           RET
            0089                   STRUCTURES      ENDP
            0089                   CODE    ENDS
                                         END
 
            Microsoft (R) Macro Assembler  Version 4.00             4/16/89 23:15:19
 
            Фиг. 6.14 Структуры                               Symbols-1
 
            Structures and Records:
 
                        N a m e                 Width   # fields
                                          Shift   Width   Mask    Initial
 
            FCB  . . . . . . . . . . . . . .          0025    000A
            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. Этот способ
    определения данных особенно подходит для часто используемых
    структур данных. Использование имен полей в качестве значений
    смещений очень удобно при модификации структур данных на этапе
    разработки программы. Если вы внесете изменения в структуру данных,
    то ассемблер автоматически изменит значения смещений при повторном
    ассемблировании программы. Кроме того, использование структур
    данных делает программу на языке ассемблера более читабельной и
    понятной.




Содержание раздела