You basically want to divide by 10, print the remainder (one digit), and then repeat with the quotient.
您基本上想要除以10,打印余数(一位数),然后重复商数。
; assume number is in eax
mov ecx, 10
loophere:
mov edx, 0
div ecx
; now eax <-- eax/10
; edx <-- eax % 10
; print edx
; this is one digit, which we have to convert to ASCII
; the print routine uses edx and eax, so let's push eax
; onto the stack. we clear edx at the beginning of the
; loop anyway, so we don't care if we much around with it
push eax
; convert dl to ascii
add dl, '0'
mov ah,2 ; 2 is the function number of output char in the DOS Services.
int 21h ; calls DOS Services
; now restore eax
pop eax
; if eax is zero, we can quit
cmp eax, 0
jnz loophere
As a side note, you have a bug in your code right here:
顺便说一句,您的代码中有一个错误:
mov ax, 1 ;put 1 into ax
add ax, 2 ; add 2 to ax current value
mov ah,2 ; 2 is the function number of output char in the DOS Services.
mov dl, ax ; DL takes the value.
You put 2
in ah
, and then you put ax
in dl
. You're basically junking ax
before printing it.
你把2放入ah,然后把ax放入d1。你基本上是在打印之前把斧头扔进垃圾桶。
You also have a size mismatch since dl
is 8 bits wide and ax
is 16 bits wide.
还有一个大小不匹配,因为dl是8位宽,而ax是16位宽。
What you should do is flip the last two lines and fix the size mismatch:
您应该做的是翻转最后两行并修复大小不匹配的问题:
mov ax, 1 ;put 1 into ax
add ax, 2 ; add 2 to ax current value
mov dl, al ; DL takes the value.
mov ah,2 ; 2 is the function number of output char in the DOS Services.
Just fixing the order of @Nathan Fellman 's code
只是修改@内森·费尔曼的S代码的顺序
PrintNumber proc
mov cx, 0
mov bx, 10
@@loophere:
mov dx, 0
div bx ;divide by ten
; now ax <-- ax/10
; dx <-- ax % 10
; print dx
; this is one digit, which we have to convert to ASCII
; the print routine uses dx and ax, so let's push ax
; onto the stack. we clear dx at the beginning of the
; loop anyway, so we don't care if we much around with it
push ax
add dl, '0' ;convert dl to ascii
pop ax ;restore ax
push dx ;digits are in reversed order, must use stack
inc cx ;remember how many digits we pushed to stack
cmp ax, 0 ;if ax is zero, we can quit
jnz @@loophere
;cx is already set
mov ah, 2 ;2 is the function number of output char in the DOS Services.
@@loophere2:
pop dx ;restore digits from last to first
int 21h ;calls DOS Services
loop @@loophere2
ret
PrintNumber endp
The basic algorithm is:
基本算法是:
divide number x by 10, giving quotient q and remainder r
emit r
if q is not zero, set x = q and repeat
Note that this will yield the digits in the inverse order, so you are probably going to want to replace the "emit" step with something that stores each digit, so that you can later iterate in reverse over the stored digits.
请注意,这将以相反的顺序生成数字,因此您可能希望用存储每个数字的内容替换“emit”步骤,以便稍后可以对存储的数字进行反向迭代。
Also, note that to convert a binary number between 0 and 9 (decimal) to ascii, just add the ascii code for '0' (which is 48) to the number.
此外,请注意,要将0到9(十进制)之间的二进制数转换为ASCII,只需在数字上加上‘0’的ASCII代码(即48)。
mov dl, ax
This won't work as dl
and ax
have different bit sizes. What you want to do is create a loop in which you divide the 16 bit value by 10, remember the rest on the stack, and then continue the loop with the integer division result. When you reach a result of 0, clean up the stack digit by digit, adding 48 to the digits to turn them into ASCII digits, then print them.
这将不起作用,因为d1和ax具有不同的位大小。您要做的是创建一个循环,在该循环中,将16位值除以10,记住堆栈上的其余部分,然后使用整数除法结果继续循环。当结果为0时,逐位清理堆栈,在数字上加48以将其转换为ASCII数字,然后打印它们。
The accepted answer is wrong in that it displays the result reversed! That's why I write this answer today. My answer demonstrates the better technique of outputting the result in one gulp (via DOS.function 09h).
被接受的答案是错误的,因为它显示的结果是相反的!这就是我今天写下这个答案的原因。我的回答展示了一次输出结果的更好技术(通过DOS.Function 09H)。
Your code
mov ah,2 ; 2 is the function number of output char in the DOS Services.
mov dl, ax ; DL takes the value.
int 21h ; calls DOS Services
Always load the DOS function number in the instruction right before the int 21h
instruction.
Always check your sizes: you cannot move from a 16-bit register to an 8-bit register.
始终在INT 21h指令之前的指令中加载DOS功能编号。始终检查您的大小:您不能从16位寄存器转移到8位寄存器。
I think that dl
value should be in ASCII code, but I'm not sure how to convert ax
value after addition into ASCII.
Your numbers allow the use of the DOS.PrintCharacter function. To convert the value 3 into the character "3", you just need to add 48 so as to have an ASCII code in DL.
您的数字允许使用DOS.PrintCharacter函数。要将值3转换为字符“3”,您只需添加48即可在DL中使用ASCII代码。
When I add two values in 16-bit assembly, what is the best way to print the result to console?
Your example for a single-digit result
; Sum
mov al, 1
add al, 2
; Print
add al, '0'
mov dl, al
mov ah, 02h ; DOS.PrintCharacter
int 21h
; Exit
mov ax, 4C00h ; DOS.TerminateWithExitcode
int 21h
Solution for a multi-digit result
; Sum
mov ax, 7346
add ax, 913
; Print
mov bx, Buffer + 5 ; Position of the mandatory '$' terminator
mov cx, 10
More:
xor dx, dx
div cx
dec bx
add dl, '0' ; Convert to ASCII
mov [bx], dl
test ax, ax
jnz More
mov dx, bx
mov ah, 09h ; DOS.PrintString
int 21h
; Exit
mov ax, 4C00h ; DOS.TerminateWithExitcode
int 21h
; Storage
Buffer: db '.....$'
NASM use mov bx, Buffer + 5
MASM use mov bx, OFFSET Buffer + 5
NASM使用MOV BX,缓冲区+5 MASM使用MOV BX,偏移缓冲区+5
更多回答
I could be wrong, but I believe your code prints the numbers in reverse. E.g.: 123 prints 321
我可能是错的,但我相信你的代码打印的数字是相反的。例如:123打印321
This prints in reverse order, least-significant digit first. Store into a buffer like *p-- = digit
, starting at the end and working backwards, to make a string. Or see Displaying numbers with DOS
这将以相反的顺序打印,最不重要的数字在前。存储到像*p--=Digit这样的缓冲区中,从末尾开始,向后操作,以生成一个字符串。或参见使用DOS显示数字
@PeterCordes: I think that this is just what sidon wrote in his answer below: stackoverflow.com/a/5812104/1084
@PeterCordes:我认为这正是Sidon在下面的回答中所写的:stackoverflow.com/a/5812104/1084
Yes. I think I noticed the same thing after commenting here and moving on to look at the other answers. This one is accepted and significantly upvoted so it should still get fixed, so I decided to leave that comment in place.
是。我想,在评论了这里并继续查看其他答案后,我注意到了同样的事情。这一条被接受了,而且得到了很大的支持,所以它仍然应该得到修复,所以我决定保留这条评论。
@ErikEidt: 32-bit registers are accessible in 16-bit modes on a 386 or later. The question doesn't specify 8086, and some future readers might not have the same restriction. So that's not a showstopper, unlike printing numbers backwards which is why I downvoted it.
@ErikEidt:在386或更高版本上,可在16位模式下访问32位寄存器。这个问题没有具体说明8086,未来的一些读者可能不会有同样的限制。因此,这并不是一个噱头,不像向后打印数字,这就是我否决它的原因。
The push ax
/ pop ax
in the first loop is pointless, and distracting when combined with pushing digits in a loop. add dl, '0'
doesn't affect AX. (You moved the int 21h
call out of the first loop vs. Nathan's version but didn't take out the save/restore of AX). Two loops with digits on the stack is one way to do this, but storing backwards into a buffer is often good like Sep's answer shows.
第一个循环中的PUSH AX/POP AX是没有意义的,当与循环中的按下数字结合时会分散注意力。添加dl,‘0’不影响AX。(您将int 21h调用移出了第一个循环,而不是Nathan的版本,但没有删除AX的保存/恢复)。堆栈上有两个带数字的循环是实现这一点的一种方法,但向后存储到缓冲区通常是很好的,如Sep的答案所示。
我是一名优秀的程序员,十分优秀!