#assembly #dos #tasm
#сборка #dos #tasm
Вопрос:
О боже… С чего мне вообще начать? Я БЕСЧИСЛЕННОЕ количество раз пытался получить простую программу, которая вычисляет площадь поверхности блока (всего за 4 или менее шагов умножения) и возвращает общую площадь. Я попытался определить программу так, чтобы основными переменными были слова, а затем снова были байты. но, несмотря ни на что, я продолжаю получать ответ, который не совпадает. моя программа не содержит ошибок или предупреждений, так что пока это хороший знак. Я пробовал умножение со знаком и без знака, но, похоже, ничего не работает. К сожалению, я не могу использовать двойные слова, поскольку у меня нет подходящего программного обеспечения. Ниже приведена моя программа:
INCLUDE io.h
Cr EQU 0DH ; carriage return
Lf EQU 0AH ; line feed
TheStack SEGMENT STACK
DW 100H DUP (?)
TheStack ENDS
Data SEGMENT
a Dw ?
b Dw ?
c Dw ?
d Dw ?
f Dw ?
g Dw ?
h Dw ?
e dw '2'
Int1 db 6 DUP (?), 0
Int2 db 6 DUP (?), 0
SUM Db 6 DUP (?), 0
Int3 Db 6 DUP (?), 0
Prompt1 DB 'Please enter the height: ', 0
Prompt2 DB Cr, Lf, 'Enter the width: ', 0
Prompt3 DB Cr, Lf, 'Enter the length: ', 0
String DB 40 DUP (?)
Label1 DB Cr, Lf, 'The sum is '
result1 DB 10 DUP (?), 0
Data ENDS
Code SEGMENT
ASSUME Cs:Code, Ds:Data
Start: Mov Ax, SEG Data ; Load Data Segment Number.
Mov Ds, Ax
Prompt: Output Prompt1 ; Prompt for first number.
Inputs String, 40 ; Read the ASCII characters.
AToI String ; Convert ASCII to Integer.
Mov a, ax; Store first number.
Output Prompt2 ; Prompt for second number.
Inputs String, 40
AToI String
Mov b, dx ; Store second number.
Mul dx; Add second number.
mov d, ax
itoa result1, ax
output result1
Output Prompt3
Inputs String, 40
AToI String
Mov c, Dx ; Store second number
Mul dx; Add second number.
mov f, dx
output f
Mov b, dx
Mov c, ax
mul dx
mov g, ax
ATOI g
mov g, ax
ATOI f
mov f, ax
ATOI d
mov d, ax
add ax, f
add ax, g
mov h, ax
output h
AToI e
mov e, ax
mov h, dx
mul dx
itoa result1, ax
output result1
Quit: Mov Al, 0 ; Put return code of zero in Al.
Mov Ah, 4CH ; Put DOS function call in Ah.
int 21H ; Call DOS
Code ENDS
END Start
Я приношу извинения за плохие объяснения в коде, поскольку я скопировал его суть из предыдущей программы. теперь я не понимаю, как некоторые совершенно определенные переменные могут возвращать неправильные значения. Я даже изменил переменные, но мне все еще не повезло. Это и сбивает с толку, и раздражает. Чтобы представить это в перспективе, когда я пытаюсь умножить 1 на 1, возвращаемое значение равно 402, что далеко от истины! Я новичок в программировании на ассемблере, поэтому я действительно считаю, что частично это связано с неопытностью. Мой вопрос в том, как эта безошибочная программа в конечном итоге возвращает неправильные значения, когда она, казалось бы, собрана правильно и проверена множество раз на наличие ошибок? Есть ли недостающий фрагмент? Нужно ли мне полностью переписывать ее? Это ошибка эмулятора? Что не так с кодом, из-за чего кажущаяся идеальной программа работает неправильно?
Комментарии:
1. Используйте отладчик, чтобы вы могли выполнить один шаг через него и проверить регистры / память. Ваши
ATOI
,itoa
илиoutput
функции сохраняют / восстанавливают DX? Я думаю, что вижу по крайней мере один случай, когда вы используете DX сразу после вызоваoutput
. В большинстве соглашений о вызовах DX не сохраняется при вызове. Вы не показываете код для них или не говорите, из какой библиотеки они взяты.2. Если ваша программа считывает только два числа от пользователя, почему она вызывает ATOI более двух раз? Просто преобразуйте все в целое число сразу после прочтения. Тогда вы можете хранить данные в регистрах без кучи вызовов функций и загрузок / хранилищ между вашей математикой. (На современном процессоре цикл сохранения / перезагрузки в оба конца занимает около 5 циклов, что больше, чем умножение. Забота о количестве умножений в принципе не имеет значения по сравнению с количеством вещей, которые выполняет этот код : P)
3. Вы понимаете, что умножение двух 16-битных значений возвращает 32-битное значение, а умножение двух 8-битных значений возвращает 16-битное значение? Вероятно, вам следует внимательно ознакомиться с документацией для
MUL
иIMUL
и убедиться, что вы случайно не оставляете данные.
Ответ №1:
из того, что я вижу, коробка имеет 6 сторон, по 2 с каждой стороны одинакового размера:
2 квадрата x на y
2 квадрата x на z
2 квадрата y на z
поверхность коробки является суммой всех
итак, все, что вам нужно, это:
сохраните введенные длины в [side_x], в [side_x] и [side_z]. Тогда вычисление суммы всех 3 пар квадратов могло бы выглядеть следующим образом (это практически оптимизировано)
start: mov ax,[side_x] ; side x*y
mov bx,[side_y]
mov dx,0
mul bx
shl ax,1 ; 2 times
mov [box_size],ax
; 2 sides x*z
mov ax,[side_x]
mov bx,[side_z]
mov dx,0
mul bx
shl ax,1
add ax,[box_size]
mov [box_size],ax
; 2 sides y*z
mov ax,[side_y]
mov bx,[side_z]
mov dx,0
mul bx
shl ax,1
add ax,[box_size]
mov [box_size],ax
затем распечатайте [box_size] и готово
примечание: конечно, это работает только тогда, когда размер поля соответствует 16-разрядному регистру (< 65536), поэтому «верхняя часть» умножения (в dx) игнорируется
Комментарии:
1. Я пробовал это, и даже после этого я все еще не получаю возвращенного правильного значения. Предполагается, что я запрашиваю у пользователя размеры, а затем умножаю их. Я даже не уверен, что я делаю неправильно! У меня такое чувство, что я просто бегаю по кругу.
2. к черту это, я просто попробовал это с заранее определенными переменными, и это работает. но не с переменными, которые я хочу определить через приглашение. Странно. Интересно, что я делаю не так.
3. ага! Выяснил, что я сделал не так! Это было прямо у меня под носом! Я ввел третье приглашение слишком рано. Итак, почему, черт возьми, я это пропустил? лол
4. нет, подождите, неважно, что они все еще были предопределены. Выстрел… Похоже, что dosbox является большой проблемой без всякой причины. Я поместил следующее перед каждой новой стороной:
5. вывод prompt3 Вводит строку, 40 ; Считывает символы ASCII. Строка AToI