我正在使用汇编库来创建一个从标准输入中读取三个整数的程序。当在控制台中完成读取时,它可以正常工作,但是当我使用文件作为输入时,它会立即读取三个整数。
这是控制台的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 --------------------
答案 0 :(得分:1)
您需要缓冲输入并将其拆分,因为控制台和文件的行为略有不同。一旦有人按下 Return ,控制台就会立即向您发送数据。
每次调用read()
时,文件都会向您发送尽可能多的数据。
要使代码正常工作,您必须编写一个readline()
函数,逐字节读取输入,并在看到换行符时返回。
或者您可以使用内部缓冲区,尽可能多地填充数据,查找第一行,返回,重复直到缓冲区为空,尝试读取更多数据,当没有更多数据时返回EOF输入。
答案 1 :(得分:0)
正如Aaron指出的那样,问题是sys_read
在重定向stdin
时表现不同。你可以按照他的建议修复它。或者您可以使用Along32的ReadString
并使用“自制”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
;------------------------
;--------------------
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,真的)包含停止处理的“无效”字节。我认为您可以在返回的字符串上重复调用它,保存整数(在eax中)并再次调用它(不接触edx)如果ecx是LF。当ecx为零时,你已经完成了。希望你觉得它有用。