How to convert negative integer to string and output it in MASM Assembly

Viewed 1501

I am supposed to take signed integers from a user, calculate the sum of inputted numbers and then display the average. The problem is, negative numbers don't seem to be displaying correctly, although I know the sum and average are being calculated correctly.

What do I need to add to my procedure to account for negative numbers so they are displayed correctly?

.
.
.
writeVal PROC   USES eax
    LOCAL   resultString[11]:BYTE
    lea     eax, resultString
    push    eax
    push    [ebp + 8]
    call    intToStr
    lea     eax, resultString
    displayString eax ; print num
    ret     4

writeVal ENDP


intToStr PROC       USES eax ebx ecx
    LOCAL   tempChar:DWORD

    mov     eax, [ebp + 8]
    mov     ebx, 10
    mov     ecx, 0
    cld

divideByTen:
    cdq
    idiv    ebx
    push    edx
    inc     ecx
    cmp     eax, 0
    jne     divideByTen
    mov     edi, [ebp + 12] ; move into dest array
    jmp     storeChar

;store char in array

storeChar:
    pop     tempChar
    mov     al, BYTE PTR tempChar
    add     al, 48
    stosb
    loop    storeChar
    mov     al, 0
    stosb
    ret     8

intToStr ENDP
.
.
.
2 Answers

If the input is negative, record that fact somewhere (in a register) and neg your input number. (e.g. test eax,eax / jnl to jump over a block if it's not less-than-0, otherwise fall into the block that handles that case.)

Then do unsigned int -> string conversion (using div not idiv) the normal way into the buffer.

If you use a push/pop strategy for reversing digits, you can put a '-' into the buffer and increment your pointer right away. Otherwise, wait until the end to prepend a '-' if you're storing digits in least-signficant first order starting at the end of a buffer and decrementing a pointer (like in How do I print an integer in Assembly Level Programming without printf from the c library?)

Using unsigned handles the corner case of the most-negative integer -2147483648, bit-pattern 0x8000000. Its absolute value can't be represented as a 32-bit 2's complement positive integer, only as 32-bit unsigned.

You can simply check if the number is less than zero and then use neg instruction to negate it and apply the negative sign - to the resultString buffer:

Code for writeVal will be:

writeVal PROC USES eax ecx edi
    LOCAL   resultString[11]:BYTE
    lea     eax, resultString

    mov     ecx, [ebp + 8]          ; load passed number to ebx
    test    ecx, ecx                ; test number to see if it's less than zero
    jnl     non_negative            ; jump if not less to non_negative

    neg     ecx                     ; else we have a negative number so neg to make it positive
    mov     byte ptr [eax], '-'     ; set resultString[0] to '-'
    inc     eax                     ; increase resultString ptr + 1

    non_negative:

    push    eax                  ; push the resultString + 1
    push    ecx                  ; push the number
    call    intToStr             ; convert the number
    lea     eax, resultString
    printc  eax                  ; print num
    ret     4
writeVal ENDP

Compile and run:

start:

    push -14286754
    call writeVal

    exit

end start

Will print:

-14286754
Related