如何在程序集 x86 中使用变量
How to work with variables in assembly x86
所以我必须将 'a' 乘以 'b' 次,我试着这样做。我也从我发现的其他问题中提取了一些程序。
.MODEL SMALL
.DATA
a db 3, 4 dup (0)
b db 3, 4 dup (0) ;With the buffer that this provides, this now will allow you to input from the keyboard two double-digit numbers.
.CODE
mov ax, @data ;INITIALIZE DATA SEGMENT.
mov ds, ax
START:
;a
mov ah, 0ah
mov dx, offset a
int 21h
call string2number1 ;convert a to number (a->bx)
mov dx,bx ;(a->ax)
;b
mov ah, 0ah
mov dx, offset b
int 21h
call string2number2 ;convert b to number (b->bx)
;multiplication
mov cx,bx ;b->cx (multiply by cx(b) times)
mov bx,dx ;a->bx (to do a*a)
power:
mul bx
loop power
;dx:ax should now contain m^n (i hope)
;displaying dx:ax
mov bx,10 ;CONST
push bx ;Sentinel
.a: mov cx,ax ;Temporarily store LowDividend in CX
mov ax,dx ;First divide the HighDividend
xor dx,dx ;Setup for division DX:AX / BX
div bx ; -> AX is HighQuotient, Remainder is re-used
xchg ax,cx ;Temporarily move it to CX restoring LowDividend
div bx ; -> AX is LowQuotient, Remainder DX=[0,9]
push dx ;(1) Save remainder for now
mov dx,cx ;Build true 32-bit quotient in DX:AX
or cx,ax ;Is the true 32-bit quotient zero?
jnz .a ;No, use as next dividend
pop dx ;(1a) First pop (Is digit for sure)
.b: add dl,"0" ;Turn into character [0,9] -> ["0","9"]
mov ah,02h ;DOS.DisplayCharacter
int 21h ; -> AL
pop dx ;(1b) All remaining pops
cmp dx,bx ;Was it the sentinel?
jb .b ;Not yet
;-----------------------------------------
jmp skipProcedures
;CONVERT a TO NUMBER IN BX.
proc string2number1
;MAKE SI TO POINT TO THE LEAST SIGNIFICANT DIGIT.
mov si, offset a + 1
mov cl, [ si ] ;NUMBER OF CHARACTERS ENTERED.
mov ch, 0 ;CLEAR CH, NOW CX==CL.
add si, cx ;NOW SI POINTS TO LEAST SIGNIFICANT DIGIT.
;CONVERT STRING.
mov bx, 0
mov bp, 1 ;MULTIPLE OF 10 TO MULTIPLY EVERY DIGIT.
repeat:
;CONVERT CHARACTER.
mov al, [ si ] ;CHARACTER TO PROCESS.
sub al, 48 ;CONVERT ASCII CHARACTER TO DIGIT.
mov ah, 0 ;CLEAR AH, NOW AX==AL.
mul bp ;AX*BP = DX:AX.
add bx,ax ;ADD RESULT TO BX.
;INCREASE MULTIPLE OF 10 (1, 10, 100...).
mov ax, bp
mov bp, 10
mul bp ;AX*10 = DX:AX.
mov bp, ax ;NEW MULTIPLE OF 10.
;CHECK IF WE HAVE FINISHED.
dec si ;NEXT DIGIT TO PROCESS.
loop repeat ;COUNTER CX-1, IF NOT ZERO, REPEAT.
ret
endp
;CONVERT b TO NUMBER IN BX.
proc string2number2
;MAKE SI TO POINT TO THE LEAST SIGNIFICANT DIGIT.
mov si, offset b + 1
mov cl, [ si ] ;NUMBER OF CHARACTERS ENTERED.
mov ch, 0 ;CLEAR CH, NOW CX==CL.
add si, cx ;NOW SI POINTS TO LEAST SIGNIFICANT DIGIT.
;CONVERT STRING.
mov bx, 0
mov bp, 1 ;MULTIPLE OF 10 TO MULTIPLY EVERY DIGIT.
repeat2:
;CONVERT CHARACTER.
mov al, [ si ] ;CHARACTER TO PROCESS.
sub al, 48 ;CONVERT ASCII CHARACTER TO DIGIT.
mov ah, 0 ;CLEAR AH, NOW AX==AL.
mul bp ;AX*BP = DX:AX.
add bx,ax ;ADD RESULT TO BX.
;INCREASE MULTIPLE OF 10 (1, 10, 100...).
mov ax, bp
mov bp, 10
mul bp ;AX*10 = DX:AX.
mov bp, ax ;NEW MULTIPLE OF 10.
;CHECK IF WE HAVE FINISHED.
dec si ;NEXT DIGIT TO PROCESS.
loop repeat2 ;COUNTER CX-1, IF NOT ZERO, REPEAT.
ret
endp
skipProcedures:
;---------------------------------------
mov ax,4c00h
int 21h
end start
程序不让我在输入 'a' 后按回车键。
也许我在做乘法循环或试图显示 dx:ax 时错了,但这与让我为 a 写输入有什么关系?
我试图在评论中尽可能多地解释。
我该怎么办?
I keep getting the same error as 'Operand types do not match on lines 18 and 19
那是因为 TASM 知道 a 和 b 变量是 byte-sized 给定的它们是使用 DB
指令定义的,但是您的指令 mov bx,a
和 mov cx,b
是 word-sized 操作。所以,一个不匹配。
这就是代码中发生的事情
您的程序正在使用 a 和 b 'variables' 通过 DOS.BufferedInput 函数 0Ah 进行用户输入.阅读有关此功能的所有信息 。
您的定义应该是这样的:
.DATA
a db 3, 4 dup (0)
b db 3, 4 dup (0)
有了它提供的缓冲区,现在您可以从键盘输入两个两位数。
要真正开始使用这些数字进行计算,您需要将文本字符(输入它们的字符)转换为 [0,99] 范围内的简单数字。
下一个代码为 两位数 a 输入完成此操作:
mov bx, offset a
mov ah, [bx+2] ; The tens ["0","9"]
mov al, [bx+3] ; The ones ["0","9"]
sub ax, "00" ; Converting to [0,9] on both at the same time
aad ; Combining both: AX = (AH * 10) + AL
mov ax,0 ; Initial result, i.e. m^0
power:
jcxz power_done
mul bx
loop power
power_done:
无论乘以什么值 (BX
),此乘法始终为零。那是因为你初始化了AX=0
。这与注释“初始结果,即 m^0”不对应。请记住 m^0 = 1
.
您正在尝试使用单字符输出函数显示结果。这永远都不够!请参阅 this Q/A 了解正确的方法。
所以我必须将 'a' 乘以 'b' 次,我试着这样做。我也从我发现的其他问题中提取了一些程序。
.MODEL SMALL
.DATA
a db 3, 4 dup (0)
b db 3, 4 dup (0) ;With the buffer that this provides, this now will allow you to input from the keyboard two double-digit numbers.
.CODE
mov ax, @data ;INITIALIZE DATA SEGMENT.
mov ds, ax
START:
;a
mov ah, 0ah
mov dx, offset a
int 21h
call string2number1 ;convert a to number (a->bx)
mov dx,bx ;(a->ax)
;b
mov ah, 0ah
mov dx, offset b
int 21h
call string2number2 ;convert b to number (b->bx)
;multiplication
mov cx,bx ;b->cx (multiply by cx(b) times)
mov bx,dx ;a->bx (to do a*a)
power:
mul bx
loop power
;dx:ax should now contain m^n (i hope)
;displaying dx:ax
mov bx,10 ;CONST
push bx ;Sentinel
.a: mov cx,ax ;Temporarily store LowDividend in CX
mov ax,dx ;First divide the HighDividend
xor dx,dx ;Setup for division DX:AX / BX
div bx ; -> AX is HighQuotient, Remainder is re-used
xchg ax,cx ;Temporarily move it to CX restoring LowDividend
div bx ; -> AX is LowQuotient, Remainder DX=[0,9]
push dx ;(1) Save remainder for now
mov dx,cx ;Build true 32-bit quotient in DX:AX
or cx,ax ;Is the true 32-bit quotient zero?
jnz .a ;No, use as next dividend
pop dx ;(1a) First pop (Is digit for sure)
.b: add dl,"0" ;Turn into character [0,9] -> ["0","9"]
mov ah,02h ;DOS.DisplayCharacter
int 21h ; -> AL
pop dx ;(1b) All remaining pops
cmp dx,bx ;Was it the sentinel?
jb .b ;Not yet
;-----------------------------------------
jmp skipProcedures
;CONVERT a TO NUMBER IN BX.
proc string2number1
;MAKE SI TO POINT TO THE LEAST SIGNIFICANT DIGIT.
mov si, offset a + 1
mov cl, [ si ] ;NUMBER OF CHARACTERS ENTERED.
mov ch, 0 ;CLEAR CH, NOW CX==CL.
add si, cx ;NOW SI POINTS TO LEAST SIGNIFICANT DIGIT.
;CONVERT STRING.
mov bx, 0
mov bp, 1 ;MULTIPLE OF 10 TO MULTIPLY EVERY DIGIT.
repeat:
;CONVERT CHARACTER.
mov al, [ si ] ;CHARACTER TO PROCESS.
sub al, 48 ;CONVERT ASCII CHARACTER TO DIGIT.
mov ah, 0 ;CLEAR AH, NOW AX==AL.
mul bp ;AX*BP = DX:AX.
add bx,ax ;ADD RESULT TO BX.
;INCREASE MULTIPLE OF 10 (1, 10, 100...).
mov ax, bp
mov bp, 10
mul bp ;AX*10 = DX:AX.
mov bp, ax ;NEW MULTIPLE OF 10.
;CHECK IF WE HAVE FINISHED.
dec si ;NEXT DIGIT TO PROCESS.
loop repeat ;COUNTER CX-1, IF NOT ZERO, REPEAT.
ret
endp
;CONVERT b TO NUMBER IN BX.
proc string2number2
;MAKE SI TO POINT TO THE LEAST SIGNIFICANT DIGIT.
mov si, offset b + 1
mov cl, [ si ] ;NUMBER OF CHARACTERS ENTERED.
mov ch, 0 ;CLEAR CH, NOW CX==CL.
add si, cx ;NOW SI POINTS TO LEAST SIGNIFICANT DIGIT.
;CONVERT STRING.
mov bx, 0
mov bp, 1 ;MULTIPLE OF 10 TO MULTIPLY EVERY DIGIT.
repeat2:
;CONVERT CHARACTER.
mov al, [ si ] ;CHARACTER TO PROCESS.
sub al, 48 ;CONVERT ASCII CHARACTER TO DIGIT.
mov ah, 0 ;CLEAR AH, NOW AX==AL.
mul bp ;AX*BP = DX:AX.
add bx,ax ;ADD RESULT TO BX.
;INCREASE MULTIPLE OF 10 (1, 10, 100...).
mov ax, bp
mov bp, 10
mul bp ;AX*10 = DX:AX.
mov bp, ax ;NEW MULTIPLE OF 10.
;CHECK IF WE HAVE FINISHED.
dec si ;NEXT DIGIT TO PROCESS.
loop repeat2 ;COUNTER CX-1, IF NOT ZERO, REPEAT.
ret
endp
skipProcedures:
;---------------------------------------
mov ax,4c00h
int 21h
end start
程序不让我在输入 'a' 后按回车键。 也许我在做乘法循环或试图显示 dx:ax 时错了,但这与让我为 a 写输入有什么关系? 我试图在评论中尽可能多地解释。 我该怎么办?
I keep getting the same error as 'Operand types do not match on lines 18 and 19
那是因为 TASM 知道 a 和 b 变量是 byte-sized 给定的它们是使用 DB
指令定义的,但是您的指令 mov bx,a
和 mov cx,b
是 word-sized 操作。所以,一个不匹配。
这就是代码中发生的事情
您的程序正在使用 a 和 b 'variables' 通过 DOS.BufferedInput 函数 0Ah 进行用户输入.阅读有关此功能的所有信息
您的定义应该是这样的:
.DATA
a db 3, 4 dup (0)
b db 3, 4 dup (0)
有了它提供的缓冲区,现在您可以从键盘输入两个两位数。
要真正开始使用这些数字进行计算,您需要将文本字符(输入它们的字符)转换为 [0,99] 范围内的简单数字。
下一个代码为 两位数 a 输入完成此操作:
mov bx, offset a
mov ah, [bx+2] ; The tens ["0","9"]
mov al, [bx+3] ; The ones ["0","9"]
sub ax, "00" ; Converting to [0,9] on both at the same time
aad ; Combining both: AX = (AH * 10) + AL
mov ax,0 ; Initial result, i.e. m^0 power: jcxz power_done mul bx loop power power_done:
无论乘以什么值 (BX
),此乘法始终为零。那是因为你初始化了AX=0
。这与注释“初始结果,即 m^0”不对应。请记住 m^0 = 1
.
您正在尝试使用单字符输出函数显示结果。这永远都不够!请参阅 this Q/A 了解正确的方法。