datasg ends
codesg segment para ‘Code’
mov ax,0bad4h ; загрузить в ax шестнадцатеричную константу
. . . ; (первый 0 показывает, что это константа) mov ax,bad4h ; загрузить ax из переменной в памяти bad4h
; (отсутствие 0 в качестве первого символа показывает, что это метка)
. . .
codesg ends
В общем случае постоянным числовым значением может быть только операнд, начинающийся с цифр 0-9.
Числа с плавающей точкой могут обозначаться двумя способами (см.
уч. пос., ч.4).
Чтобы показать, что число является десятичным, в качестве суффикса можно использовать букву d. Наконец, могут использоваться символьные константы, при этом символы заключаются в одиночные или двойные кавычки. Значением символа является его значение кода ASCII. Например, все следующие строки загружают в регистр al значение кода ASCII
символа А [1, с. 559]. |
|
|
mov |
al,65 |
; 65 = 41h |
mov |
al,41h |
|
mov |
al,'A' |
; ASCII код символа А = 41h |
mov |
al,"A" |
; ASCII код символа А = 41h |
Двоичные, восьмеричные, десятичные и шестнадцатеричные значения могут использоваться там же, где можно использовать константы.
4.50. Инициализированные данные
Директивы определения данных db, dw, dd, dq и dt позволяют определить переменные в памяти различного размера: один байт (db), два байта, т.е. одно слово (dw), четыре байта, т.е. двойное слово (dd), восемь байтов, т.е. одно учетверенное слово (dq) и десять байтов (dt).
Например:
datasg segment para ‘Data’
ByteVar db 'Z' |
; 1 |
байт |
WordVar dw 101b |
; 2 |
байта (1 слово) |
DwordVardd 2BFh |
; 4 |
байта (1 двойное слово) |
QwordVar dq 307o |
; 8 |
байтов (1 учетверенное слово) |
TwordVardt 100 |
; 10 байтов |
|
datasg ends
codesg segment para ‘Code’
. . .
mov ah,2 ; функция DOS вывода на дисплей
56
mov dl,ByteVar ; символ, который нужно вывести на экран int 21h
mov ax,WordVar
. . .
add word ptr DwordVar,ax adc word ptr DwordVar+2,dx
. . .
codesg ends
Здесь определяются пять переменных памяти и показывается, как некоторые из таких переменных можно использовать.
4.51.Инициализация массивов
Водной директиве определения данных может указываться несколько значений. Например, директива:
SampleArrray dw 0, 1, 2, 3, 4
создает массив из пяти элементов с именем SampleArray, элементы которого имеют размер в слово. В директивах определения данных можно использовать любое число значений, умещающееся на строке.
Если нужно определить массив, который слишком велик и не вмещается на одной строке, нужно добавить несколько строк. Метку в директиве определения данных указывать необязательно. Например, по директивам:
SquareArray dd 0, 1, 4, 9, 16 dd 25, 36, 49, 64, 81
dd 100, 121, 144, 169, 196
создается массив элементов размером в двойное слово с именем SquareArray, состоящий из квадратов первых 15 целых чисел.
Ассемблер позволяет определить блок памяти, инициализированный указанным значением, с помощью операции dup. Например,
BlankArraydw 100h dup (0)
Здесь создается массив BlankArray, состоящий из 256 слов (подругому: 100h), инициализированных значением 0. Аналогично директива:
ArrayOf_A db 92 dup ('A')
создает массив из 92 байтов, и каждый инициализирован символом A.
4.52.Инициализация строк символов
Строку символов можно определить следующим образом:
Stringdb 'A', 'B', 'C', 'D'
Предусмотрена также удобная сокращенная форма:
String db 'ABCD'
Чтобы переместиться к левому краю следующей строки, нужно вывести символы "возврат каретки/перевод строки". Например:
57
stacksg segment para ‘Stack’ db 256 dup (0)
stacksg ends
datasg segment para ‘Data’
String1 db |
'Line1','$' |
|
String2 db |
'Line2','$' |
|
String3 db |
'Line3','$' |
|
datasg ends |
|
|
codesg segment para ‘Code’ |
||
ProgramStart: |
|
|
mov ax,datasg |
|
|
mov ds,ax |
|
|
mov ah,9 |
|
; функция DOS печати строки |
mov dx,offset String1 |
; печатаемая строка |
|
int 21h |
|
; вызвать DOS для печати строки |
mov dx, offset String2 |
; печатаемая строка |
|
int 21h |
|
; вызвать DOS для печати строки |
mov dx, offset String3 |
; печатаемая строка |
|
int 21h |
|
; вызвать DOS для печати строки |
mov ah,4ch |
; функция DOS завершения программы |
|
int 21h codesg ends
end ProgramStart
Программа печатает следующее:
Line1Line2Line3
Однако если в конце каждой строки добавить символы "возврат каретки/перевод строки":
String1 db 'Line1',0dh,0ah,'$' String2 db 'Line2',0dh,0ah,'$' String3 db 'Line3',0dh,0ah,'$'
то вывод будет выглядеть следующим образом:
Line1
Line2
Line3
4.53. Инициализация выражений и меток
Начальное значение инициализированной переменной должно представлять собой константу, но это не обязательно должно быть число.
58
Можно также использовать: выражения:
TestVar dw ((924/2)+1); TestVar инициализируется значением 463
и метки:
datasg segment para ‘Data’
db 1,2,3,4,5,6,7,8,9,10,10,9,8,7,6,5,4,3,2,1
Buffer dw 16 dup (0) ; область памяти из 16-ти нулевых слов
BufferPointer dw Buffer datasg ends
Начальное значение BufferPointer представляет собой смещение Buffer в сегменте datasg, а не значение 0, которое хранится в переменной Buffer. В результате этого и инструкция:
mov ax,offset Buffer
и инструкция:
mov ax,BufferPointer
загрузят в регистр ax одно и то же значение (смещение переменной Buffer, которое в приведенном выше примере равно 20, т.к. в сегменте данных перед областью данных с меткой Buffer располагается 20 байтов данных).
В выражениях определения данных допускается использовать метки. Например, переменная WordArrayLength инициализируется значением длины (в байтах) WordArray:
datasg segment para ‘Data’
WordArray dw 50 dup (0); массив из 50-ти нулевых слов
WordArrayEnd label word
WordArrayLength dw (WordArrayEnd - WordArray);длина = 100 datasg ends
Если требуется вычислить длину переменной WordArray в словах, а не в байтах, это можно сделать, просто разделив длину в байтах на 2:
WordArrayLength dw (WordArrayEnd - WordArray) / 2
4.54. Неинициализированные данные
Иногда нет смысла присваивать переменной памяти начальное значение. Тогда применяют знак вопроса (?). Например:
KeyBuffer db 10 dup (?)
В данной строке резервируется 10 байтов памяти, начиная с метки KeyBuffer, но этим байтам не присваивается никакого конкретного значения.
Конечно, при использовании неинициализированной переменной ее нужно инициализировать в своей программе перед тем, как использовать. Например, было бы ошибочным использовать содержимое KeyBuffer до
59
того, как этот массив будет заполнен, так как находящиеся в KeyBuffer начальные значения не определены.
4.55. Именованные ячейки памяти
Кроме присвоения имени ячейке памяти с помощью метки, предшествующей директиве определения данных (например, db), можно присваивать имя ячейке директивой label, которая позволяет определить имя метки и ее тип, не определяя при этом данные. Например, в предыдущем примере массив KeyBuffer можно определить так:
KeyBuffer label byte db 10 dup (?)
Типы меток, которые можно определить с помощью label, включают в себя: byte, word, dword, qword, tbyte, proc, near, far, unknown и др.
Типы byte (байт), word (слово), dword (двойное слово), qword (учетверенное слово) и tbyte (десять байтов) говорят сами за себя, определяя, соответственно, 1-, 2-, 4-, 8- и 10-байтовые элементы данных. Приведем пример инициализации переменной, как пары байтов, но обращения к ней, как к слову:
datasg segment para ‘Data’ WordVar label word
db 1,2 datasg ends
codesg segment para ‘Code’
. . .
mov ax,[WordVar]
. . .
Когда эта программа выполняется, в регистр al загружается 1 (первый байт WordVar), а в регистр ah – значение 2.
Ключевые слова near и far используются в программе для выбора типа вызова или перехода, необходимого для достижения определенной метки. Например, в программе:
codesg segment para ‘Code’
. . .
FarLabel label far NearLabel label near
mov ax,1
. . .
jmp FarLabel
. . .
jmp NearLabel
. . .
60