程序集8086打印有符号的单个数字整数

时间:2017-04-24 16:50:26

标签: assembly x86-16 emu8086

我写了一个程序来获取数组中最小的数字, 但是我无法在屏幕上打印出来:(( 我认为问题是将其转换为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装配保护模式的书,请在此处提及:))

2 个答案:

答案 0 :(得分:1)

您的代码有两个问题(除了显示负数)

1. NUM变量中的零点

如果您的数组包含非零数字,例如:enumerate,它应该打印1作为其最小数字,但是您的代码将打印0,这在数组中甚至不存在。

2.使用JNB和JB说明

这些说明仅用于正整数,请查看JNB JB。您必须使用JNGJG,因为您的数组包含负数。

以下是检查数组中最小数字的程序(无论是否包含负数或正数,它都适用于两种情况,它还显示如何打印负数):

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

您不需要分别使用单独的SFZF指示来测试jsjz。如果原始数字为负数,我会在jle之后使用neg,因为它会根据0 - num设置标记。如果jle0 <= num,即num为非负数,我们就不会打'-'

我本可以做到

 test bl, bl
 jge  posNum

因为test same,same sets flags identically to cmp bl, 0。当然,jge用于大于或等于零的数字。

请注意,0 - 128会溢出,因此仅在neg之后测试SF并不等同于jlejle是正确的,js不是。

但我们的打印首先只处理一位数的整数。如果您拥有的是什么,请在打印可选'-'后使用多个多位数字函数之一将绝对值打印为无符号整数。