1

我正在使用一个汇编库来制作一个从标准输入中读取三个整数的程序。当在控制台中完成读取时,它工作得很好,但是当我使用文件作为输入时,它会一次读取三个整数。

这是控制台的 strace:

read(0, "3000\n", 512)                  = 5
read(0, "2000\n", 512)                  = 5
read(0, "1000\n", 512)                  = 5

这来自输入文件:

read(0, "3000\n2000\n1000\n", 512)      = 15
read(0, "", 512)                        = 0
read(0, "", 512)                        = 0

以下是程序:

;--------------------------------------------------------
ReadInt:
;
; Reads a 32-bit signed 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 + or - sign is permitted.
; All spaces return a valid integer, value zero.
; Receives: nothing
; Returns:  If CF=0, the integer is valid, and EAX = binary value.
;   If CF=1, the integer is invalid and EAX = 0.
;--------------------------------------------------------

    push edx
    push ecx
; Input a signed decimal string.

    mov   edx,digitBuffer
    mov   ecx,MAX_DIGITS
    call  ReadString
    mov   ecx,eax   ; save length in ECX

; Convert to binary (EDX -> string, ECX = length)

    call    ParseInteger32  ; returns EAX, CF

    pop ecx
    pop edx
    ret
;--------------- End of ReadInt ------------------------

;--------------------------------------------------------
ReadString:
;
; Reads a string from the keyboard and places the characters
; in a buffer.
; Receives: EDX offset of the input buffer
;           ECX = maximum characters to input (including terminal null)
; Returns:  EAX = size of the input string.
; Comments: Stops when Enter key (0Dh,0Ah) is pressed. If the user
; types more characters than (ECX-1), the excess characters
; are ignored.
; Written by Kip Irvine and Gerald Cahill
; Modified by Curtis Wong
;--------------------------------------------------------
    enter 8, 0    ; bufSize: ebp - 4
              ; bytesRead: ebp - 8
    pushad

    mov edi,edx     ; set EDI to buffer offset
    mov dword [ebp - 4],ecx     ; save buffer size

    call ReadKeys

    mov dword [ebp - 8], eax

    cmp eax,0
    jz  .L5         ; skip move if zero chars input

    cld     ; search forward
    mov ecx, dword [ebp - 4]    ; repetition count for SCASB
    dec ecx
    mov al,NL   ; scan for 0Ah (Line Feed) terminal character
    repne scasb
    jne .L1     ; if not found, jump to L1

    ;if we reach this line, length of input string <= (bufsize - 2)

    dec dword [ebp - 8]     ; second adjustment to bytesRead
    dec edi         ; 0Ah found: back up two positions
    cmp edi,edx         ; don't back up to before the user's buffer
    jae .L2
    mov edi,edx         ; 0Ah must be the only byte in the buffer
    jmp .L2     ; and jump to L2

.L1:    mov edi,edx     ; point to last byte in buffer
    add edi,dword [ebp - 4]
    dec edi
    mov byte [edi],0            ; insert null byte

    ; Clear excess characters from the buffer, 1 byte at a time
.L6:    call BufferFlush
    jmp .L5

.L2:    mov byte [edi],0        ; insert null byte

.L5:    popad
    mov eax, dword [ebp - 8]
    leave
    ret
;--------------- End of ReadString --------------------
4

2 回答 2

1

您需要缓冲输入并将其拆分,因为控制台和文件的行为略有不同。一旦有人按下Return,控制台就会向您发送数据,即逐行发送。

文件将在每次调用时向您发送尽可能多的数据read()

为了使您的代码正常工作,您必须编写一个readline()函数,逐字节读取输入,并在看到换行时返回。

或者您可以使用内部缓冲区,用尽可能多的数据填充它,找到第一行,返回,重复直到缓冲区为空,尝试读取更多数据,当输入没有更多数据时返回 EOF。

于 2013-09-10T12:52:51.823 回答
0

正如 Aaron 指出的那样,问题在于重定向sys_read时的行为不同。stdin你可以按照他的建议修复它。或者您可以使用Along32ReadString并使用“自制” atoi

;--------------------
atoi:
    push ebx

    mov edx, [esp + 8]  ; pointer to string
    xor ebx, ebx ; assume not negative

    cmp byte [edx], '-'
    jnz notneg
    inc ebx ; indicate negative
    inc edx ; move past the '-'
notneg:

    xor eax, eax        ; clear "result"
.top:
    movzx ecx, byte [edx]
    inc edx
    cmp ecx, byte '0'
    jb .done
    cmp ecx, byte '9'
    ja .done

    ; we have a valid character - multiply
    ; result-so-far by 10, subtract '0'
    ; from the character to convert it to
    ; a number, and add it to result.

    lea eax, [eax + eax * 4]
    lea eax, [eax * 2 + ecx - '0']

    jmp short .top
.done:
    test ebx, ebx
    jz notminus
    neg eax
notminus:
    pop ebx
    ret
;------------------------

这期望字符串的地址被压入堆栈并在之后“删除”,但我认为你可以注释掉第二行,并在 edx 中传递地址(未经测试!)。更像是这样的Along32代码的其余部分。与Along32 的代码不同,它返回edx 指向下一个字节,而ecx(实际上只是cl)包含停止处理的“无效”字节。我认为你可以在返回的字符串上重复调用它ReadString,保存整数(在 eax 中)并再次调用它(不接触 edx)如果 ecx 是 LF。当 ecx 为零时,您就完成了。希望对您有所帮助。

于 2013-09-10T13:51:44.740 回答