assembly 如何在x86汇编中接受更大的输入?

hm2xizp9  于 2023-04-06  发布在  其他
关注(0)|答案(1)|浏览(131)

这个程序以一个非负整数作为输入,并确定它是否是素数。问题是4000000007需要作为输入,但是失败了。我知道问题是这个数字太大了,并且位于MyReadInt proc中的某个地方,但是我不知道如何修复它。我只包括了影响错误的代码。当输入40000000007时,控制台返回TryAgain消息。

INCLUDE Irvine32.inc

.DATA
startTime DWORD ?
enter1 BYTE "Enter a non-negative integer (0 to exit): ",0
tryAgain BYTE "That input is not allowed. Try again.",0
prime BYTE " is a prime number.",0
notPrime BYTE " is not a prime number; it is divisible by: ",0
exitMessage BYTE "Goodbye",0
time BYTE "Procedure runtime in milliseconds: ",0
LMAX_DIGITS = 80
Linputarea BYTE LMAX_DIGITS dup(0),0
overflow_msgL BYTE " <32-bit integer overflow>",0
invalid_msgL BYTE " ",0 
neg_msg BYTE " ",0

.code
main PROC
beginning: mov edx, OFFSET enter1 
           call WriteString     ; writes null-terminated string to standard output
           call myReadInt.          ; input stored in eax 
           cmp eax, 0               ; compares eax to 0
           jge noError          ; continue if input >= 0
           mov edx, OFFSET tryAgain ; if number is negative, write error message
           call writeString     ; writes null-terminated string to standard output
           jmp beginning        ; loop beginning 
        
main ENDP
                                    ; end of procedure
;______________________________________________________________________________
; MyReadInt PROC 
; Modified from Irvine32.asm by _________
; Reads a 32-bit unsigned decimal integer from standard
; input, stopping when the Enter key is pressed.
; All valid digits occurring before a non-numeric character
; are converted to the integer value. Leading spaces are
; ignored, and an optional leading + sign is permitted.
; Receives: nothing
; Returns: If CF=0, the integer is valid, and EAX = binary value.
; If CF=1, the integer is invalid and EAX = 0.
;______________________________________________________________________________
 MyReadInt PROC uses ebx ecx edx esi

    ; Input a string of digits using ReadString.
    mov edx,offset Linputarea
    mov esi,edx                                         ; save offset in ESI
    mov ecx,LMAX_DIGITS
    call ReadString
    mov ecx,eax                                         ; save length in ECX
    cmp ecx,0                                           ; greater than zero?
    jne L1                                              ; yes: continue
    mov eax,0                                           ; no: set return value
    jmp L9                                              ; and exit

; Skip over any leading spaces.
L1: mov al,[esi]                                    ; get a character from buffer
    cmp al,' '                                      ; space character found?
    jne L2                                          ; no: check for a sign
    inc esi                                         ; yes: point to next char
    loop L1
    jcxz L8                                         ; quit if all spaces

; Check for a leading sign.
L2: cmp al,'-'                                      ; minus sign found?
    jne L3                                          ; no: look for plus sign
    mov edx, offset neg_msg                         ; tell user negative numbers not allowed
    jmp L8

L3: cmp al,'+'                                      ; plus sign found?
    jne L4                                          ; no: must be a digit
    inc esi                                         ; yes: skip over the sign
    dec ecx                                         ; subtract from counter

; Test the first digit, and exit if it is nonnumeric.
L3A:mov al,[esi]                                    ; get first character
    call IsDigit                                    ; is it a digit?
    jnz L7A                                         ; no: show error message

; Start to convert the number.
    L4: mov eax,0                                   ; clear accumulator
    mov ebx,10                                      ; EBX is the divisor

; Repeat loop for each digit.
L5: mov dl,[esi]                                    ; get character from buffer
    cmp dl,'0'                                      ; character < '0'?
    jb L10
    cmp dl,'9'                                      ; character > '9'?
    ja L10
    and edx,0Fh                                     ; no: convert to binary
    push edx
    mul ebx                                         ; EDX:EAX = EAX * EBX
    pop edx
    jo L6                                           ; quit if result too big for 32 bits
    add eax,edx                                     ; add new digit to AX
    jo L6                                           ; quit if result too big for 32 bits
    inc esi                                         ; point to next digit
    jmp L5                                          ; get next digit

; Carry out of 32 bits has occured, choose "integer overflow" messsage.
L6: mov edx,OFFSET overflow_msgL
    jmp L8

; Choose "invalid integer" message.
L7A:mov edx,OFFSET invalid_msgL

; Display the error message pointed to by EDX.
L8: call WriteString
    call Crlf
    mov eax,0                                       ; set return value to zero and exit

L9: stc                                             ; set Carry flag to indicate error
    ret

L10: clc                                                ; clear Carry flag to indicate success
     ret
MyReadInt ENDP
END main
wbgh16ku

wbgh16ku1#

问题是需要将4000000007作为输入
您可能希望将 MyReadInt 重命名为 MyReadUInt,因为Unsigned**Int* 埃格是您想要的。
并且允许使用可选的前导+号
允许一个前导'+'号,有点违背了输入无符号数字的目的。

jcxz L8           ; quit if all spaces

目标 * L 8 * 期望EDX指向 invalid_msgL 的偏移量。事实并非如此!您应该将其写成:jecxz L7A(这是jecxz,而不是jcxz
以下代码将允许转换高达4GB-1:

L4:  xor   eax, eax
     mov   ebx, 10

L5:  movzx ecx, BYTE PTR [esi]
     inc   esi
     sub   ecx, '0'  ; convert to binary
     cmp   ecx, ebx
     jae   L10
     mul   ebx       ; EAX * 10
     jc    L6        ; quit if result too big for 32 bits
     add   eax, ecx  ; EAX + NewDigit
     jnc   L5        ; get next digit, if result not too big for 32 bits

L6:  mov   edx, OFFSET overflow_msgL
     jmp   L8

     ...

L10: clc             ; clear Carry flag to indicate success
     ret

当然,为了实际执行程序的其余部分,你不应该只检查EAX寄存器。而是测试进位标志:

call MyReadUInt     ; -> EAX CF
jnc  noError        ; continue if CF=0

相关问题