Ассамблея 8086 | Сумма массива, печать многозначных чисел
Я написал довольно простой код в asm x8086, и я столкнулся с ошибкой. Если бы кто-нибудь мог мне помочь с кратким объяснением, я бы очень признателен.
IDEAL
MODEL small
STACK 100h
DATASEG
; --------------------------
array db 10h, 04h, 04h, 04h, 04h, 04h, 04h, 04h, 04h, 04h
sum db 0
; --------------------------
CODESEG
start:
mov ax, @data
mov ds, ax
; --------------------------
xor cx, cx
mov al, 0
mov bx, offset array
StartLoop:
cmp cx, 10
jge EndLoop
add al, [bx]
add [sum],al
inc cx
inc bx
jmp StartLoop
EndLoop:
mov ah, 09h
int 21h
; --------------------------
exit:
mov ax, 4c00h
int 21h
END start
Ответы
Ответ 1
С исправлением для add
, которое должно быть заменено на mov
, как отмечено в вашем комментарии (обратите внимание, что строка: add al, [bx] - фактически mov al, [bx]), там просто вызов функции в ярлык EndLoop, что неправильно!
Вы хотите отобразить сумму и используете функцию печати DOS. Эта функция 09h ожидает указателя в DS: DX, который вы не предоставляете!
Даже если вы это сделали, вам все равно придется преобразовать номер суммы в его текстовое представление.
Быстрое решение здесь состояло бы в том, чтобы самому конкретизировать себя и просто отобразить результат в виде одного символа ASCII. Жестко закодированная сумма равна 52 и поэтому является отображаемым символом:
EndLoop:
mov dl, [sum]
mov ah, 02h ;Single character output
int 21h
; --------------------------
exit:
mov ax, 4c00h
int 21h
Еще один шаг, и мы можем отобразить "52":
mov al,[sum]
mov ah,0
mov dl,10
div dl ---> AL=5 AH=2
add ax,3030h ---> AL="5" AH="2"
mov dh,ah ;preserve AH
mov dl,al
mov ah,02h
int 21h
mov dl,dh ;restore
int 21h
Ответ 2
Я вообще не вижу никакой ошибки, код будет суммировать массив, отображать некоторые случайные sh * t и выходить.
Вероятно, вы хотите отобразить результат суммы?
int 21h, ah=9
отобразит '$'
завершенную строку из памяти, на которую указывает dx
.
Итак, вам нужно две вещи: преобразуйте число в [sum]
в строку, завершенную '$'
в конце, а затем установите dx
в преобразованную строку перед этим int 21h
.
Вы можете попробовать извлечь из него процедуру number2string
: fooobar.com/info/2523/...
Я лично изменил бы его, чтобы адрес целевого буфера в si
был еще одним аргументом вызова (т.е. просто удалите mov si,offset str
из тела процедуры). Вот так:
PROC number2string
; arguments:
; ax = unsigned number to convert
; si = pointer to string buffer (must have 6+ bytes)
; modifies: ax, bx, cx, dx, si
mov bx, 10 ; radix 10 (decimal number formatting)
xor cx, cx ; counter of extracted digits set to zero
number2string_divide_by_radix:
; calculate single digit
xor dx, dx ; dx = 0 (dx:ax = 32b number to divide)
div bx ; divide dx:ax by radix, remainder will be in dx
; store the remainder in stack
push dx
inc cx
; loop till number is zero
test ax, ax
jnz number2string_divide_by_radix
; now convert stored digits in stack into string
number2string_write_string:
pop dx
add dl, '0' ; convert 0-9 value into '0'-'9' ASCII character encoding
; store character at end of string
mov [si], dl
inc si
; loop till all digits are written
dec cx
jnz number2string_write_string
; store '$' terminator at end
mov BYTE PTR [si],'$'
ret
ENDP
Затем, чтобы вызвать это на вашем EndLoop
, вам нужно добавить в сегмент данных numberStr DB 8 DUP (0)
, чтобы иметь буфер памяти, выделенный для строки, и добавить в код:
; load sum as 16b unsigned value into ax
xor ax,ax ; ax = 0
mov al,[sum] ; ax = sum (16b zero extended)
; convert it to string
mov si,OFFSET numberStr
call number2string
; display the '$' terminated string
mov dx,OFFSET numberStr
mov ah,9
int 21h
; ... exit ...