我写了一个程序来获取数组中最小的数字, 但是我无法在屏幕上打印出来:(( 我认为问题是将其转换为ASCII。
.model small
.stack 100h
.data
x db 0,5,-1,4,2 ;my array
min db 0 ;variable to store the smallest number
msg db "The min number is: $"
.code
main PROC
mov ax,@data
mov ds,ax
xor cx,cx
mov cl,5 ;set count to 5
mov si,0 ;start at index 0
L1:
mov dl,x[si] ;can't compare memory to memory so I moved x[si] to dl
cmp min,dl ;checks to see if the value in dl is smaller than
;value in min
JNB no
mov min,dl
no:
inc si
loop L1
mov ah,09
mov dx,offset msg ;print the message
int 21h
cmp min,0 ;check if number is negative or positive
JB minus
mov ah,02
mov dl,min
int 21h
minus: ;if minus print the minus sign
mov ah,02
mov dl,'-'
int 21h
*mov ah,02
mov dl,min
or dl,30h ;here's my error can't print value of min
int 21h*
mov ah,04ch ;exit code
int 21h
main ENDP
END main
如果有人有好的资料或学习80386装配保护模式的书,请在此处提及:))
答案 0 :(得分:1)
您的代码有两个问题(除了显示负数)
1. NUM变量中的零点
如果您的数组包含非零数字,例如:enumerate
,它应该打印1作为其最小数字,但是您的代码将打印0,这在数组中甚至不存在。
2.使用JNB和JB说明
这些说明仅用于正整数,请查看JNB JB。您必须使用JNG和JG,因为您的数组包含负数。
以下是检查数组中最小数字的程序(无论是否包含负数或正数,它都适用于两种情况,它还显示如何打印负数):
5, 4, 7, 1
答案 1 :(得分:1)
相关:在16位模式的现代x86 CPU上,您可以使用SSE4.1 phminposuw
进行范围转换,使其适用于带符号的输入。您可以在一条指令中找到8个元素中的最小值:x86 Assembly - 2 largest values out of 4 given numbers。使用pmovsxbw xmm0, [num]
加载带符号的字节。
实现min-finding循环的一种更有效的方法是避免slow loop
instruction,并且当没有新的min时避免采用分支(除了循环分支)。我可以通过使用loop
和/或使用常规jge
来跳过循环中的指令,而不是通过正常的代码,使代码更小不跑。
相关:Assembly program that finds second largest value in array。我在那里使用了类似的循环结构。
与终点指针进行比较是有效的,无论它是常数还是寄存器。作为一个立即,它保存循环外的指令。我们也不需要将CX
与循环计数器联系起来;我们已经有SI
中的指针。
这个答案的要点是用于打印主要-
,like I mentioned in comments on @Ahtisham's answer的更紧凑的代码。请参阅下面main
的第2部分。
.model small
.stack 100h
.data
num db 0,5,-1,4,2 ;my array
numEnd:
numSize = numEnd - num
msg db "The min number is: $"
.code
main PROC
mov ax, @data
mov ds, ax
mov si, OFFSET num
mov bl, [si] ; bl = min
calMin: ; do {
cmp si, OFFSET numEnd-1
jae endloop ; if (p >= end-1) break;
inc si ; p++
cmp bl, [si]
jle calMin ; if (*p <= min) continue; signed compare
; on new min, fall through and update BL before continuing
mov bl, [si] ; min = *p
jmp calMin ; } while(1);
endloop:
;;; BL = min. Do whatever you want with it.
现在我们在bl
中有了数组的最小值。
通常情况下,您需要加载到寄存器而不是使用多个加载,但mov al, [si]
仅在大多数输入中很少运行。重新加载相同的值很快(因为缓存)所以在常见情况循环中保存指令是一种胜利,即使它在我们找到新的最小值时意味着额外的负载。
如果min
中有一个一位数签名bl
,我们就可以打印它(如果它为负数,则为-
):< / p>
; we could print the message before the loop
; if we wanted to avoid clobbering registers.
mov ah, 09h ; print a message first
mov dx, offset msg
int 21h ; al = write string to stdout(ds:dx)
mov dl, bl ; in case it's positive
neg bl ; bl = 0 - bl setting flags accordingly
jle posNum ; if (0 <= num) skip the leading '-'
mov ah, 02h
mov dl, '-' ; print minus symbol if negative number
int 21h ; al = print char to stdout(dl)
mov dl, bl ; the negated value is positive, print it
posNum:
; absolute value of single-digit number in DL
mov ah, 02h
add dl, '0'
int 21h ; al = print char to stdout(dl)
exit:
mov ax, 04c00h ; AL = 0 (exit status), AH = 4C (Exit function)
int 21h
main ENDP
END main
您不需要分别使用单独的SF
和ZF
指示来测试js
和jz
。如果原始数字为负数,我会在jle
之后使用neg
,因为它会根据0 - num
设置标记。如果jle
即0 <= num
,即num
为非负数,我们就不会打'-'
。
我本可以做到
test bl, bl
jge posNum
因为test same,same
sets flags identically to cmp bl, 0
。当然,jge
用于大于或等于零的数字。
请注意,0 - 128
会溢出,因此仅在neg
之后测试SF并不等同于jle
。 jle
是正确的,js
不是。
但我们的打印首先只处理一位数的整数。如果您拥有的是什么,请在打印可选'-'
后使用多个多位数字函数之一将绝对值打印为无符号整数。