汇编新手请求帮助:有符号整数除法 + "truncating to an integer"
Assembly newbie requesting help: signed integer division + "truncating to an integer"
几天前我问了一个关于这段代码的问题,所以你们中的一些人可能会觉得它很熟悉。对于那些不熟悉的人,这段代码应该做的是从用户那里请求 25 个带符号的整数并将它们存储到一个数组中;这是通过 requestSignedInts 子例程完成的(我很确定这部分工作正常)。之后,"calcMean" 子程序应该将数组中的所有值相加,除以数组中元素的数量,然后 "truncate the result to an integer"。这就是我被困的地方。我试图编写一个 calcMean 子例程来执行我刚才描述的操作,但似乎无法弄清楚如何正确地进行除法。最重要的是,我什至不确定我目前在我的 calcMean 子例程中拥有的东西是否能正常工作。谁能提供帮助?
INCLUDE c:\irvine\irvine32.inc
INCLUDELIB c:\irvine\irvine32.lib
INCLUDELIB c:\masm32\lib\user32.lib
INCLUDELIB c:\masm32\lib\kernel32.lib
.data
theSINTArray BYTE 25 dup(?)
lengthOfArray BYTE ?
indexCounter BYTE 0
prompt BYTE "Please enter a value: ",0
.CODE
main PROC
call requestSignedInts
call calculateMean
exit
main ENDP
requestSignedInts PROC
mov edx, offset theSINTArray
Next:
push edx
mov edx,OFFSET prompt
call WriteString
call ReadInt
pop edx
mov [edx], al
inc edx
cmp edx, offset theSINTArray + 25
jb Next
ret
requestSignedInts ENDP
calculateMean PROC
push ecx
mov ecx,lengthOfArray - theSINTArray ; Determine array length
xor eax, eax ; Clear EAX
mov esi, OFFSET theSINTArray ; Starting point for index into array
calcMean:
movsx edx, byte ptr[esi] ; Sign extended move a byte into EDX
add eax, edx ; Accumulate in EAX
inc esi ; Increment source pointer to the next element
loop calcMean ; or cmp esi,endOfArray / jb, then you wouldn't need to touch ecx
mov ecx,lengthOfArray - theSINTArray ; Determine array length
cdq ; sign-extend eax into edx:eax
idiv ecx ; Divide edx:eax by ecx
; eax now contains the integer and edx contains
; the remainder.
pop ecx
ret
calculateMean ENDP
END main
在我看来,您可能错过了评论中提到的 idiv
的功能。为什么不呢:
calculateMean PROC
push ecx
mov ecx,lengthOfArray - theSINTArray ; Determine array length
xor eax, eax ; Clear EAX
mov esi, theSINTArray ; Starting point for index into array
calcMean:
movsx edx, byte ptr[esi] ; Sign extended move a byte into EDX
add eax, edx ; Accumulate in EAX
inc esi ; Increment source pointer to the next element
loop calcMean ; or cmp esi,endOfArray / jb, then you wouldn't need to touch ecx
mov ecx,lengthOfArray - theSINTArray ; Determine array length
cdq ; sign-extend eax into edx:eax
idiv ecx ; Divide edx:eax by ecx
; eax now contains the integer and edx contains
; the remainder.
pop ecx
ret
calculateMean ENDP
你已经知道列表的长度,你只需要清除edx
并除以ecx
。这也正确地使用 movsx
将字节(从您的数组)符号扩展移动到 32 位寄存器 (edx
)。总数累加到 eax
,最后,我们签署扩展和除法。
您的原始代码比 David 的回答更奇怪。我发布了一个新答案,而不是进一步编辑 David 的答案。
更改会在评论中注明。旧评论已删除,以便更改说明脱颖而出。
.data
SBYTEArray BYTE 25 dup(?) ; SINT = signed int, which makes most x86 C programmers think 32bit
; lengthOfArray BYTE ? ; totally bogus: named wrong, and there doesn't need to be any storage there
; SBYTEArray_len equ $ - SBYTEArray ; that's NASM syntax and IDK the MASM syntax
SBYTEArray_end: ; SBYTEArray_end and prompt have the same address. That's fine.
prompt BYTE "Please enter a value: ",0 ; If MASM/Windows has a .rodata section, you should put constant data there. It goes in the text section, along with code, because each instance of your process doesn't need a private copy.
.CODE
main PROC
call requestSignedInts
call calculateMean
exit
main ENDP
requestSignedInts PROC
; indent code one level deeper than labels / directives
push esi ; save a call-preserved reg
mov esi, offset SBYTEArray
Next:
mov edx,OFFSET prompt
call WriteString
call ReadInt
mov [esi], al
inc esi
; cmp edx, offset SBYTEArray + 25 ; hard-coding the size defeats the purpose of defining lengthOfArray
cmp esi, offset SBYTEArray_end
jb Next
pop esi ; note that the push/pop are outside the loop
ret
requestSignedInts ENDP
calculateMean PROC
; push ecx ; The normal function-call ABIs allow clobbering ecx, and I don't see any reason to make this function go beyond the ABI requirements (although that is an option in asm)
; push esi ; esi *is* call-preserved in the standard 32bit ABIs. But by changing our function to use fewer registers, we can avoid the save/restore
xor eax, eax ; start with sum=0
mov ecx, offset SBYTEArray
calcMean:
movsx edx, byte ptr[ecx]
add eax, edx
inc ecx
cmp ecx, offset SBYTEArray_end
jb calcMean ; loop while our pointer is below the end pointer
mov ecx, SBYTEArray_end - SBYTEArray ; Determine array length. Does this need OFFSET?
cdq
idiv ecx
; pop esi ; we ended up not needing it
ret
calculateMean ENDP
END Main
loop
is slow, avoid it. Esp。当你可以通过使用其他东西作为你的循环条件来保存寄存器时。
几天前我问了一个关于这段代码的问题,所以你们中的一些人可能会觉得它很熟悉。对于那些不熟悉的人,这段代码应该做的是从用户那里请求 25 个带符号的整数并将它们存储到一个数组中;这是通过 requestSignedInts 子例程完成的(我很确定这部分工作正常)。之后,"calcMean" 子程序应该将数组中的所有值相加,除以数组中元素的数量,然后 "truncate the result to an integer"。这就是我被困的地方。我试图编写一个 calcMean 子例程来执行我刚才描述的操作,但似乎无法弄清楚如何正确地进行除法。最重要的是,我什至不确定我目前在我的 calcMean 子例程中拥有的东西是否能正常工作。谁能提供帮助?
INCLUDE c:\irvine\irvine32.inc
INCLUDELIB c:\irvine\irvine32.lib
INCLUDELIB c:\masm32\lib\user32.lib
INCLUDELIB c:\masm32\lib\kernel32.lib
.data
theSINTArray BYTE 25 dup(?)
lengthOfArray BYTE ?
indexCounter BYTE 0
prompt BYTE "Please enter a value: ",0
.CODE
main PROC
call requestSignedInts
call calculateMean
exit
main ENDP
requestSignedInts PROC
mov edx, offset theSINTArray
Next:
push edx
mov edx,OFFSET prompt
call WriteString
call ReadInt
pop edx
mov [edx], al
inc edx
cmp edx, offset theSINTArray + 25
jb Next
ret
requestSignedInts ENDP
calculateMean PROC
push ecx
mov ecx,lengthOfArray - theSINTArray ; Determine array length
xor eax, eax ; Clear EAX
mov esi, OFFSET theSINTArray ; Starting point for index into array
calcMean:
movsx edx, byte ptr[esi] ; Sign extended move a byte into EDX
add eax, edx ; Accumulate in EAX
inc esi ; Increment source pointer to the next element
loop calcMean ; or cmp esi,endOfArray / jb, then you wouldn't need to touch ecx
mov ecx,lengthOfArray - theSINTArray ; Determine array length
cdq ; sign-extend eax into edx:eax
idiv ecx ; Divide edx:eax by ecx
; eax now contains the integer and edx contains
; the remainder.
pop ecx
ret
calculateMean ENDP
END main
在我看来,您可能错过了评论中提到的 idiv
的功能。为什么不呢:
calculateMean PROC
push ecx
mov ecx,lengthOfArray - theSINTArray ; Determine array length
xor eax, eax ; Clear EAX
mov esi, theSINTArray ; Starting point for index into array
calcMean:
movsx edx, byte ptr[esi] ; Sign extended move a byte into EDX
add eax, edx ; Accumulate in EAX
inc esi ; Increment source pointer to the next element
loop calcMean ; or cmp esi,endOfArray / jb, then you wouldn't need to touch ecx
mov ecx,lengthOfArray - theSINTArray ; Determine array length
cdq ; sign-extend eax into edx:eax
idiv ecx ; Divide edx:eax by ecx
; eax now contains the integer and edx contains
; the remainder.
pop ecx
ret
calculateMean ENDP
你已经知道列表的长度,你只需要清除edx
并除以ecx
。这也正确地使用 movsx
将字节(从您的数组)符号扩展移动到 32 位寄存器 (edx
)。总数累加到 eax
,最后,我们签署扩展和除法。
您的原始代码比 David 的回答更奇怪。我发布了一个新答案,而不是进一步编辑 David 的答案。
更改会在评论中注明。旧评论已删除,以便更改说明脱颖而出。
.data
SBYTEArray BYTE 25 dup(?) ; SINT = signed int, which makes most x86 C programmers think 32bit
; lengthOfArray BYTE ? ; totally bogus: named wrong, and there doesn't need to be any storage there
; SBYTEArray_len equ $ - SBYTEArray ; that's NASM syntax and IDK the MASM syntax
SBYTEArray_end: ; SBYTEArray_end and prompt have the same address. That's fine.
prompt BYTE "Please enter a value: ",0 ; If MASM/Windows has a .rodata section, you should put constant data there. It goes in the text section, along with code, because each instance of your process doesn't need a private copy.
.CODE
main PROC
call requestSignedInts
call calculateMean
exit
main ENDP
requestSignedInts PROC
; indent code one level deeper than labels / directives
push esi ; save a call-preserved reg
mov esi, offset SBYTEArray
Next:
mov edx,OFFSET prompt
call WriteString
call ReadInt
mov [esi], al
inc esi
; cmp edx, offset SBYTEArray + 25 ; hard-coding the size defeats the purpose of defining lengthOfArray
cmp esi, offset SBYTEArray_end
jb Next
pop esi ; note that the push/pop are outside the loop
ret
requestSignedInts ENDP
calculateMean PROC
; push ecx ; The normal function-call ABIs allow clobbering ecx, and I don't see any reason to make this function go beyond the ABI requirements (although that is an option in asm)
; push esi ; esi *is* call-preserved in the standard 32bit ABIs. But by changing our function to use fewer registers, we can avoid the save/restore
xor eax, eax ; start with sum=0
mov ecx, offset SBYTEArray
calcMean:
movsx edx, byte ptr[ecx]
add eax, edx
inc ecx
cmp ecx, offset SBYTEArray_end
jb calcMean ; loop while our pointer is below the end pointer
mov ecx, SBYTEArray_end - SBYTEArray ; Determine array length. Does this need OFFSET?
cdq
idiv ecx
; pop esi ; we ended up not needing it
ret
calculateMean ENDP
END Main
loop
is slow, avoid it. Esp。当你可以通过使用其他东西作为你的循环条件来保存寄存器时。