2016-04-12 5 views
1

Несколько дней назад я задал вопрос относительно этого кода, поэтому некоторые из вас могут найти его знакомым. Для тех из вас, кто не знаком с этим, что этот код должен делать, это запросить 25 знаковых целых чисел от пользователя и сохранить их в массиве; это делается с помощью подпрограммы requestSignedInts (я уверен, что эта часть работает правильно). Впоследствии подпрограмма «calcMean» должна складывать все значения в массиве, делить их на количество элементов в массиве и затем «обрезать результат до целого числа». Здесь я застрял. Я попытался написать подпрограмму 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 
+3

Отдел уже усекает до целого числа, так что просто ничего не делайте. Кстати, помните о роли 'edx' в разделении. – harold

+0

Команда «idiv» дает целочисленный результат. Как говорит @harold, просто ничего не делайте, результат уже усечен в EAX (http://www.cs.virginia.edu/~evans/cs216/guides/x86.html). –

+0

@harold Если есть «роль» для edx, я, к сожалению, не знаю, что это такое. Я предполагаю, что эта «роль», как ожидается, будет здравым смыслом, но, будучи новичком на этом языке, у меня еще нет всех оснований. Что такое роль edx? – Proto

ответ

2

Мне кажется, что вы, возможно, отсутствует функция 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 и, наконец, мы подпишем расширение и разделим.

+1

Если 'eax' может быть отрицательным, вам нужно подписать расширение' eax' в 'edx: eax' с инструкцией' cdq'. Используйте либо 'xor edx, edx' /' div', либо 'cdq' /' idiv'. –

+0

Абсолютно верно. Казалось, что OP не понимает, как idiv может работать в своем коде. Я добавлю cdq утром, когда буду на моей клавиатуре. –

+0

Существует еще много чего сказать о том, как OP должен загружать байты с помощью 'movsx' перед накоплением в регистр 4B и что' [edx + indexCounter] 'использует адрес indexCounter, а не его значение. Я сделал редактирование 'cdq', но я оставлю все для вас ... –

1

Существует более странное о вашем исходном коде, чем ответ Дэвида. Я отправляю новый ответ вместо дальнейшего редактирования Дэвида.

Изменения отмечены в комментариях. Старые комментарии удалены, поэтому заметки изменений выделяются.

.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. когда вы можете сохранить регистр, используя что-то еще для вашего условия цикла.