Глава 12. Определение данных

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

          Все директивы  определения  данных  имеют  некоторые   общие
     средства.  Во  первых  они  могут генерировать инициализированные
     данные и резервировать место для неинициализированных данных. Для
     инициализированных данных определяется некоторое начальное значе-
     ние. Неинициализированные данные определяются без задания началь-
     ного значения (говорят,  что их начальное значение является неоп-
     ределенным). В директивах определения данных неинициализированные
     данные указываются с помощью символа ?.  Все прочее должно предс-
     тавлять значение инициализированных данных.  О том,  как  следует
     различать инициализированные и неинициализированные данные, расс-
     казывается в Главе 7.

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

          [имя_директивы [выражение_dup [выражение_dup.]]

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

          Каждое "выражение_dup" может иметь следующий синтаксис:

          - ?;

          - значение;

          - выражение_счетчик DUP( выражение_dup[,выражение_dup.]);

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

          Если вы хотите получить неинициализированные данные, исполь-
     зуйте идентификатор ?.  Объем резервируемой для неиницализирован-
     ных данных памяти зависит от фактически используемой директивы.

          "Значение" предназначено для фактического описания отдельно-
     го элемента  данных  в  каждой директиве.  В некоторых директивах
     поле значения может быть очень сложным и содержать много  элемен-
     тов, другие могут потребовать только простого выражения.

          В следующем примере используется директива DW, которая выде-
     ляет слова:

          DW 2 DUP (3 DUP (1,3),5) ; эквивалентно директиве
                                   ; DS 1,3,1,3,1,35,1,3,1,3,1,3,5


Простые директивы определения данных

Вы можете определять данные с помощью директив DB, DW, DD, DQ, DF, DP или DT. Как показано в следующей таблице, эти директи- вы выделяют простые данные различного размера: Директивы определения данных различного размера Таблица 12.1 ---------------T------------------------------------------------¬ ¦ Директива ¦ Значение ¦ +--------------+------------------------------------------------+ ¦ DB ¦ Определение данных размером в байт. ¦ ¦ ¦ ¦ ¦ DW ¦ Определение данных размером в слово. ¦ ¦ ¦ ¦ ¦ DD ¦ Определение данных размером в двойное слово. ¦ ¦ ¦ ¦ ¦ DQ ¦ Определение данных размером в четверное слово.¦ ¦ ¦ ¦ ¦ DF ¦ Определение данных размером в 6 байт (48-бито-¦ ¦ ¦ вый дальний указатель процессора 80386). ¦ ¦ ¦ ¦ ¦ DP ¦ Определение данных размером в 6 байт (48-бито-¦ ¦ ¦ вый дальний указатель процессора 80386). ¦ ¦ ¦ ¦ ¦ DT ¦ Определение данных размером в 10 байт. ¦ L--------------+------------------------------------------------- Синтаксис поля "значение" для каждой из этих директив разли- чается и основывается на возможности представлять отдельные вели- чины с помощью данных определенного размера (например, байтовые данные нельзя интерпретировать, как число с плавающей точкой). В директиве DB (байт) можно задавать следующие значения: - Выражение-константу, имеющую значения в диапазоне от -128 до 255 (байты со знаком в диапазоне от -128 до +127; безз- наковые байтовые значения в диапазоне от 0 до 255). - 8-битовое относительное выражение, использующее операции HIGH и LOW. - Символьную строку из 1 или более символов с использование стандартного формата заключенной в кавычки строки. В этом случае определяется несколько байт, по одному на каждый символ строки. Значениями директивы DW (слово) могут быть: - Выражение-константа в диапазоне от -32768 до 65535 (слова со знаком в диапазоне от -32768 до 32767, беззнаковые сло- ва в диапазоне от 0 до 65535). - Относительное выражение, занимающее 16 или менее бит (включая смещение в 16-битовом сегменте, сегмент или зна- чение группы). - Одно- или двухбайтовая строка в стандартном формате (стро- ка, заключенная в кавычки). Значениями директивы DD (двойное слово) могут быть: - Выражение-константа в диапазоне от -2147483648 до 4294967295 (при выборе процессора 80386) или от -32768 до 65535 в противном случае. - Относительное адресное выражение, состоящее из 16-битового сегмента и 16-битового смещения. - Строка длиной до 4 символов в стандартном формате (строка, заключенная в кавычки). Значениями директивы DQ (четверное слово) могут быть: - Выражение-константа в диапазоне от -2147483648 до 4294967295 (при выборе процессора 80386) или от -32768 до 65535 в противном случае. - Относительное или адресное выражение, состоящее из 32 или менее бит (при выборе процессора 80386) или 16 или менее бит (для всех других процессоров). - Положительная или отрицательная константа, имеющая значе- ние в диапазоне от -2 с 63 степени до 2 в степени 63-1 (четверное слово со знаком в диапазоне от 2 в 63 степени до 2 в степени 63-1, беззнаковое четверное слово в диапа- зоне от 0 до 2 в степени 64-1). - Строка длиной до 8 байт в стандартном формате (строка, за- ключенная в кавычки). Значениями директив DF и DP (48-битовый дальний указатель процессора 80386) могут быть: - Выражение-константа в диапазоне от -2147483648 до 4294967295 (при выборе процессора 80386) или от -32768 до 65535 в противном случае. - Относительное или адресное выражение, состоящее из 32 или менее бит (при выборе процессора 80386) или 16 или менее бит (для всех других процессоров). - Относительное адресное выражение, состоящее из 16-битового сегмента и 16-битового смещения. - Положительная или отрицательная константа, имеющая значе- ние в диапазоне от -2 в 47 степени до 2 в степени 48-1 (6- байтовое значение со знаком в диапазоне от 2 в 47 степени до 2 в степени 47-1, беззнаковое 6-байтовое значение в ди- апазоне от 0 до 2 в степени 48-1). - Строка длиной до 6 байт в стандартном формате (строка, за- ключенная в кавычки). Значениями директивы DT могут быть: - Выражение-константа в диапазоне от -2147483648 до 4294967295 (при выборе процессора 80386) или от -32768 до 65535 в противном случае. - Относительное или адресное выражение, состоящее из 32 или менее бит (при выборе процессора 80386) или 16 или менее бит (для всех других процессоров). - Относительное адресное выражение, состоящее из 16-битового сегмента и 16-битового смещения. - Положительная или отрицательная константа, имеющая значе- ние в диапазоне от -2 в 79 степени до 2 в степени 80-1 (10 -байтовое значение со знаком в диапазоне от 2 в 79 степени до 2 в степени 79-1, беззнаковое 10-байтовое значение в диапазоне от 0 до 2 в степени 80-1). - Строка длиной до 10 байт в стандартном формате (строка, заключенная в кавычки). - Упакованная десятичная константа, имеющая значение в диа- пазоне от 0 до 99999999999999999999. Примечание: При сохранении данных в памяти младшее значение всегда записывается перед старшим значением. В некоторых случаях числовые и строковые константы в дирек- тивах определения простых данных отличаются от тех, которые встречаются в стандартных выражениях Турбо Ассемблера. Например, директивы DB, DP, DT и DQ воспринимают заключенные в кавычки строки, которые могут иметь большую длину, чем строки, восприни- маемые в выражениях. Заключенные в кавычки строки выделяются одинарными (') или двойными (") кавычками. Внутри строки два ограничителя указывают, что данный символ-ограничитель должен быть частью строки, напри- мер: 'what''s up doc?' представляет следующие символы: what's up doc? В качестве значения в директивах DD, DQ и DT можно указывать числа с плавающей точкой. Приведем некоторые примеры таких чисел: 1.0E30 ; означает 1.0x10^30 2.56E-21 ; означает 2.56х10^E-21 1.28E+5 ; означает 1.28х10^+5 0.025 ; означает .025 Турбо Ассемблер распознает эти числа с плавающей точкой, поскольку они содержат после начальной цифры символ точки. В MASM эти правила могут быть ослаблены, например: DD 1E30 ; допустимое значение с плавающей точкой в ; режиме MASM DD .123 ; допустимо только в режиме MASM Примечание: Для ясности вы рекомендуем всегда исполь- зовать начальную цифру и десятичную точку. Турбо Ассемблер допускает также указывать в директивах DD, DQ и DT кодированные вещественные числа. Кодированное веществен- ное число - это шестнадцатиричное число точно определенной длины. Суффикс R указывает, что число будет интерпретироваться, как ко- дированное вещественное число. Длина числа должна заполнять тре- буемое поле (плюс одна цифра, если начальной цифрой является 0. Например: DD 12345678r ; допустимое число DD 012345678r ; допустимое число DD 1234567r ; недопустимое число (слишком ; короткое) Другие значения суффиксов (D, H, O, B) действуют аналогично тем, которые указываются в обычных выражениях. Некоторые простые директивы определения данных интерпретиру- ют другие числовые константы особым образом. Например, если вы не задаете основания для значения в директиве DT, то Турбо Ассемблер использует двоично-десятичное представление (BCD). Другие дирек- тивы предполагают десятичное значение: DD 1234 ; десятичное DT 1234 ; BCD Если значение представляет собой простую положительную или отрицательную константу, используемое по умолчанию основание (за- даваемое директивой RADIX) не применяется в директивах DD, DQ и DT. Например: RADIX 16 DW 1234 ; шестнадцатиричное значение 1234 DD 1234 ; десятичное значение 1234 Примечание: Числовые константы и директива RADIX под- робнее описываются в Главе 5.

Создание экземпляра структуры или объединения

Чтобы создать экземпляр типа данных, представляющего собой структуру или объединения, используйте в качестве директивы опре- деления данных имя структуры или объединения. Предположим, нап- ример, что вы определили следующее: ASTRUC STRUC B DB "xyz" C DW 1 D DD 2 ASTRUC ENDS BUNION UNION X DW ? Y DD ? Z DB ? BUNION ENDS Тогда операторы: ATEST ASTRUC ? BTEST BUNUION ? будут создавать экземпляры структуры astruc (определяя переменную atest) и объединения bunion (определяя переменную btest). Пос- кольку в примере указывается значение неинициализированных данных ?, то начальные данные в текущий сегмент не вводятся.

Инициализация экземпляра структуры или объединения

Инициализированные экземпляры структуры несколько более сложны, чем неинициализированные. Когда вы определяете структуру, вам нужно определить используемое по умолчанию начальное значение для каждого ее элемента. (В качестве начального значения можно использовать ключевое слово ?, которое указывает, что конкретного начального значения сохранять не следует.) Когда вы создаете эк- земпляр структуры, его можно создать с использованием значений по умолчанию или переопределяемых значений. Простейший инициализиро- ванный экземпляр структуры содержит просто заданные в определении начальные значения. Например: ASTRUC {} что эквивалентно следующему: DB "xyz" DW 1 DD 2 Фигурные скобки ({}) представляет нулевой инициализатор для структуры. Значение-инициализатор определяет, что элементы (если они имеются) должны иметь начальные значения, которые следует пе- реопределить, и какими новыми значениями, если вы выделяете дан- ные для экземпляра структуры. Инициализатор в виде фигурных ско- бок имеет следующий синтаксис: { [имя_элемента = значение [,имя_элемента.]] } где "имя_элемента" - это имя элемента структуры или объединения, а "значение" - это то значение, которое вы хотите присвоить эле- менту в данном экземпляре. Чтобы указать Турбо Ассемблеру, что для элемента нужно использовать начальное значение из определения структуры или объединения, задайте нулевое значение. Значение ? показывает, что этот элемент инициализировать не нужно. Турбо Ас- семблер присваивает всем элементам, которые не указываются в ини- циализаторе, начальное значение из определения структуры или объ- единения, например: ASTRUC {C=2,D=?} эквивалентно следующему: DB "xyz" DW 2 DD ? Вы можете использовать инициализатор в виде фигурных скобок для задания значения любого элемента структуры или объединения, даже если он находится во вложенной структуре или объединении. Объединения отличаются от структур, поскольку элементы в объединении перекрывают друг друга. Будьте аккуратны, когда вы инициализируете экземпляр структуры, поскольку если несколько элементов перекрывают друг друга, Турбо Ассемблер допускает, что- бы в экземпляре только один элемент имел инициализирующее значе- ние. Например: BUNION {} допустимо, поскольку все три элемента в определении объединения являются неинициализированными. Данный оператор эквивалентен сле- дующему: BD 4 DUP (?) В данном примере 4 байта зарезервированы, поскольку размер объединения равен размеру его наибольшего элемента (в данном слу- чае DWORD). Если инициализированный элемент объединения не явля- ется наибольшим элементом объединения, то Турбо Ассемблер воспол- няет разницу, резервируя место, но не генерируя данные, например: BUNION {Z=1} эквивалентно следующему: DB 1 DB 3 DUP (?) Наконец, несколько инициализированных элементов объединения приведут к ошибке. Следующее, например, не допускается: BUNION {X=1,Z=2} Заметим, что если два или более поля объединения имеют на- чальные значения в определении объединения, то использование простого инициализатора в виде фигурных скобок также приведет к ошибке. Чтобы генерировался допустимый экземпляр, инициализатор должен устанавливать только одно значение ?. Альтернативным методом инициализации структуры или объедине- ния является использование инициализатора в виде угловых скобок (<>). Значения такого инициализатора являются неименованными, но располагаются в том же порядке, что и соответствующие элементы в определении структуры или объединения. Для этого инициализатора используется следующий синтаксис: < [значение [,значение.]] > где "значение" представляет нужное значение соответствующего эле- мента в определении структуры или объединения. Пустое значение указывает, что вы будете использовать начальное значение из опре- деления структуры или объединения. Ключевое слово ? указывает, что элемент должен быть неинициализированным. Например: ASTRUC <"ABC"',,?> эквивалентно следующему: DB "abc" DW 1 DD ? Если вы задаете меньше значений, чем имеется элементов, Тур- бо Ассемблер закончит инициализацию, используя для остальных эле- ментов начальные значения из определения структуры или объедине- ния. ASTRUC <"ABC"> ; то же, что ASTRUC <"ABC",,> Когда вы используете инициализатор в виде угловых скобок, уделите особое внимание вложенным структурам и объединениям. Для каждого уровня вложенности в таком инициализаторе требуется ука- зывать свою пару угловых скобок, благодаря чему Турбо Ассемблер будет интерпретировать каждый инициализатор вложенной структуры или объединения как отдельную единицу (совпадающее со значением в экземпляре). Оставив соответствующие угловые скобки пустыми, вы можете пропустить инициализацию данного уровня вложенности (для вложенной структуры или объединения используется значение по умолчанию, либо использовать ключевое слово ? (для неинициализи- рованной вложенной структуры или объединения). Рассмотрите, нап- ример, следующую вложенную структуру и объединение: CUNION STRUC CTYPE DB ? UNION ; начало объединения ; если CTYPE = 0, использовать следующее. STRUC CT0PAR1 DW 1 CT0PAR2 DW 2 ENDS ; если CTYPE = 1, использовать следующее. STRUC CT1PAR1 DW 3 CT1PAR2 DW 4 ENDS ENDS ; конец объединения ENDS Инициализатор в скобках для данной структуры/объединения имеет два уровня вложенности. Эта вложенность должна учитываться соответствующей парой угловых скобок в инициализаторе, например: CUNION <0,<<2,>,?>> Эта директива эквивалентна следующему: DB 0 DW 2 DB 2 DB 2 DUP (?)

Создание экземпляра записи

Чтобы создать экземпляр данных типа записи, используйте имя данного типа, как директиву выделения данных. Например, предполо- жим, что вы определили следующее: MYREC RECORD VEL:3=4,MODE:2,SIZE:4=15 Тогда оператор: MTEST MYREC ? будет создавать экземпляр записи myrec (определяя переменную mtest). В данном примере данные в сегмент не помещаются, так как задаются неинициализированные данные (?). Экземпляры записи всегда имеют размер в байт, слово или двойное слово, в зависимости от числа бит, выделенных при опреде- лении.

Инициализация экземпляров записи

При определении записи для некоторых или всех полей записи нужно задавать начальное значение. (Турбо Ассемблер предполагает, что все не заданные значения равны 0.) Простейший инициализиро- ванный экземпляр записи содержит просто заданное в определении начальное поле данных, например: MYREC {} что эквивалентно следующему: DW (4 SHL 6) + (0 SHL 4) + (15 SHL 0) ; SHL - это операция сдвига влево для выражений Фигурные скобки ({}) представляют нулевое инициализирующее значение записи. Значение инициализатора определяет, что началь- ное значение нужно переопределить, и каким именно новым значением его требуется переопределить (если вы выделяете данные для эк- земпляра записи). Инициализатор записи в фигурных скобках имеет следующий син- таксис: { [имя_поля = выражение [,имя_поля = выражение.]] } где "имя_поля" - это имя поля записи, а "выражение" - это значе- ние, которое вы хотите определить для поля в данном экземпляре. Пустое значение указывает, что вы будете использовать начальное значение поля из определения записи. Значение ? эквивалентно ну- лю. Турбо Ассемблер устанавливает для всех полей, которые не ука- зываются в инициализаторе, начальное значение, заданное в опреде- лении записи. Например: MYREC {VEL=2,SZE=?} эквивалентно следующему: DW (2 SHL 6) + (0 SHL 4) + (0 SHL 0) Альтернативным методом инициализации экземпляров записи является использование угловых скобок (<>). В этом случае скобка- ми ограничивается инициализатор. Значения инициализатора являются неименованными, но располагаются в том же порядке, что и соот- ветствующие поля в определении записи. Данный инициализатор имеет следующий синтаксис: <[выражение [,выражение.]]> где "выражение" представляет нужное значение поля соответствующей записи в определении записи. Пустое значение указывает, что вы будете использовать начальное значение из определения записи. Ключевое слово ? указывает, что это поле должно быть равно 0. Например: MYREC <,2,?> эквивалентно следующему: DW (4 SHL 6) + (2 SHL 4) + (0 SHL 0) Если вы задаете меньше значений, чем имеется полей в записи, Турбо Ассемблер завершает экземпляр, используя для оставшихся по- лей начальные значения из определения записи. MYREC <1> ; то же, что MYREC <1,,>

Создание экземпляра данных перечислимого типа

Экземпляр данных перечислимого типа вы можете создать, ис- пользую как директиву определения данных имя перечислимого типа данных. Предположим, например, что вы определили следующее: ETYPE ENUM FEE,FIE,FOO,FUM Тогда оператор: ETEST ETYPE ? будет создавать экземпляр перечислимого типа данных ETYPE (опре- деляя переменную ETEST). В данном примере, поскольку задано зна- чение неинициализируемых данных ?, начальные данные в текущем сегменте не генерируются. Экземпляры перечислимого типа данных всегда представляют со- бой байт, слово или двойное слов, в зависимости от максимального значения, представленного в данных перечислимого типа.

Инициализация экземпляра перечислимого типа данных

Вы можете использовать любое выражение, при вычисление кото- рого получается число, умещающееся в экземпляре перечислимого ти- па данных, например: ETYPE ? ; неинициализированный экземпляр ETYPE FOO ; инициализированный экземпляр, ; значение FOO ETYPE 255 ; число вне ENUM также подходит

Создание экземпляра таблицы

Для создания экземпляра таблицы используйте в качестве ди- рективы выделения данных имя таблицы. Предположим, например, что вы определили следующую таблицу: TTYPE TABLE VIRTUAL MoveProc:WORD=MoveRtn, \продолжение. VIRTUAL MsgProc:DWORD=MsgRtn, \продолжение. VIRTUAL DoneProc:WORD=DoneRtn, Тогда оператор: TTEST TTYPE ? создает экземпляр таблицы TTYPE (определяя переменную TTEST). В данном примере, поскольку задано значение неинициализируемых дан- ных ?, начальные данные в текущем сегменте не генерируются.

Инициализация экземпляров таблицы

Когда вы определяете таблицу, нужно задать начальное значе- ние для всех ее элементов. Простейший инициализированный экземп- ляр таблицы содержит просто заданные в определении начальные данные, например: TTYPE {} что эквивалентно следующему: DW MoveRtn DD MsgRtn DW DoneRtn Фигурные скобки ({}) представляют нулевое инициализирующее значение. Значение инициализатора определяет, что элементы (если они есть) имеют начальное значение, которое нужно переопределить, и каким именно новым значением его требуется переопределить при выделении данных для экземпляра таблицы. Инициализатор записи в фигурных скобках имеет следующий син- таксис: {[имя_элемента = выражение [,имя_элемента = выражение.]]} где "имя_элемента" - это имя элемента таблицы, а "выражение" - это значение, которое вы хотите определить для элемента в данном экземпляре. Пустое значение указывает, что вы будете использовать начальное значение элемента из определения таблицы. Значение ? эквивалентно нулю. Турбо Ассемблер устанавливает для всех элемен- тов, которые не указываются в инициализаторе, начальное значение, заданное в определении таблицы. Например: TTYPE {MoveProc=MoveRtn2,DoneProc=?} что эквивалентно следующему: DW MoveRtn2 DD MsgRtn DW ?

Создание и инициализация экземпляра именованного типа данных

Для создания экземпляра именованного типа данных используйте в качестве директивы выделения данных имя типа. Предположим, нап- ример, что вы определили следующий тип: NNTYPE TYPEDEF PTR BYTE Тогда оператор: NNTEST NTTYPE ? создает экземпляр именованного типа NTYPE (определяя переменную NTTEST). В данном примере, поскольку задано значение неинициали- зируемых данных ?, начальные данные в текущем сегменте не генери- руются. Способ инициализации экземпляра именованного типа зависит от типа, который этот именованный тип представляет. Например, NTTYPE в предыдущем примере - это слово, поэтому он будет инициализиро- ваться, как если бы вы следующим образом использовали директиву DW: NTTYPE 1,2,3 ; представляет указатель значений 1,2,3 DW 1,2,3 ; то же, что NTTYPE 1,2,3 Однако, если именованный тип представляет структуру или таб- лицу, то его нужно инициализировать также, как инициализируются структуры и таблицы. Например: foo STRUC f1 DB ? ENDS bar TYPEDEF foo bar {f1=1} ; должен быть инициализатор структуры

Создание экземпляра объекта

Создание экземпляра объекта в инициализированном или неини- циализированном сегменте данных полностью совпадает с созданием экземпляра структуры. Фактически, объекты в Турбо Ассемблере представляют собой структуры с некоторыми расширениями. Одним из таких расширений является элемент структуры @Mptr_<имя_объекта>. Объектный тип данных с виртуальными методами - это структу- ра, содержащая один элемент, указывающий на таблицу указателей виртуальных методов. Именем данного элемента является @Mptr_<имя_ объекта>. Обычно инициализируется с помощью конструктора метода. Однако, вы можете построить статические объекты, не имеющие конс- труктора, но инициализируемые с помощью инициализатора в сегменте данных. Если вы указываете используемое по умолчанию значение эле- мента @Mptr_<имя_объекта>, то Турбо Ассемблер будет корректно инициализировать экземпляр объекта. Другим отличием структур и объектов является то, что объекты могут наследовать элементы из предыдущих определений объекта. При подобном наследовании Турбо Ассемблер интерпретирует его, как вложенную структуру. В связи с этим для инициализации объектных данных не рекомендуется использовать угловые скобки (<>).

Создание экземпляра таблицы виртуальных методов объекта

Для каждого объекта, содержащего виртуальные методы, необхо- димо наличие доступной таблицы виртуальных методов. Правильное размещение данной таблицы определяет множество факторов, включая то, какую программную модель вы используете, хотите вы получить таблицу NEAR или FAR и т.д. Турбо Ассемблер требует от вас только размещения данной таблицы. Экземпляр последних определенных объ- ектов вы можете создать, используя псевдооперацию TBLINST, кото- рая имеет следующий синтаксис: TBLINST TBLINST определяет в качестве адреса таблицы виртуальных ме- тодов объекта @TableAddr_<имя_объекта>. Это эквивалентно следую- щему: @TableAddr_<имя_объекта> @TableAddr_<имя_объекта> {}
                       Назад | Содержание |  Вперед