2016-07-24 2 views
0

Как напечатать отрицательное число в tasm? Пожалуйста, помогите мне. Например, если я выполняю вычитание 2-7 = (- 5). Как распечатать -5?Дисплей Отрицательные числа в TASM

+3

Возможный дубликат [как использовать отрицательные числа как один в сборке?] (http://stackoverflow.com/questions/14817184/how-to-use-negative-numbers-as-one-in-assembly) – JJJ

ответ

0

Вам необходимо выполнить преобразование номера самостоятельно (например, с помощью собственной функции). В качестве примера я добавил это совместимое с TASM5 приложение Win32, хотя я уверен, что вы можете найти в Интернете бесчисленные другие примеры преобразования строк в строку.

Это может показаться большим количеством кода для такой простой цели, однако, если вы разместите «общие» функции, которые разработаны настолько, чтобы их можно было использовать в любом количестве программ во включенном файле или библиотеке, настоящая программа это только функция appMain() внизу, которая составляет всего около 10 строк кода. Я бросил все в одном файле для того, чтобы быть полным рабочим примером.

Вас интересует функция numToString(), показанная ниже, которая преобразует DWORD в число в буфере, переданном функции. Остальная часть кода - всего лишь фреймворк для вызова функции вместе с некоторыми общими оболочками WriteConsole. numToString() поддерживает преобразование чисел в любую базу (например, шестнадцатеричную и двоичную). В этом примере я передаю аргументы, чтобы указать base-10 с включенным отрицательным флагом (указывая, чтобы обработать номер DWORD как подписанный).

Алгоритм numToString() выглядит следующим образом:

-If number is to be interpreted as signed and IS negative, convert it to positive and set bHasSign flag 
-Repeatedly divide positive (in loop) number by base (radix) and convert remainder to ASCII char; this gives us each digit of the resulting string starting with the least significant digit 
-Append negative "-" to end based on bHasSign flag 
-NULL terminate destination buffer 
-Because the algorithm actually computes digits from least significant to most significant, we need to reverse the resultant string (including negative sign) before returning. In English, we read digits starting with most significant first. 
The reverse algorithm swaps the outer bytes, then the next inner bytes, and so on until it reaches the middle of the string. This swapping allows us to avoid setting up a temporary buffer for the character reversal. 

Программа выхода:

The number is: -352 

Программа листинга:

.386 
.model flat 

GetStdHandle    PROTO STDCALL :DWORD 
WriteConsoleA    PROTO STDCALL :DWORD, :DWORD, :DWORD, :DWORD, :DWORD 
ExitProcess     PROTO STDCALL :DWORD 

getStringLength    PROTO STDCALL :DWORD 
outputString    PROTO STDCALL :DWORD, :DWORD 
numToString     PROTO STDCALL :DWORD, :DWORD, :DWORD, :DWORD, :DWORD 

NULL        equ  0 
STD_OUTPUT_HANDLE     equ  -11 
MAXLEN_BINARYNUM_BUFFER    equ  33   ;max string length for number->string buffer assuming smallest base (32 bits) + NULL accounts for largest possible binary number 
MAXLEN_BINARYNUM_BUFFER_AS_DWORD equ  9   ;36-byte hack for MAXLEN_BINARYNUM_BUFFER used below so TASM doesn't mess up Win32 stack alignment 
CODE_ERROR_BUFLEN     equ  -10 

.data 

szMsg  db 'The number is: ',0 

.code 

; 
; getStringLength() - returns zero terminated string length in eax 
; 
getStringLength PROC STDCALL pszString:DWORD 

    ;count the characters in the string and store result in ecx 
    lea esi,pszString  ;make esi point to first character in string 
    mov esi,[esi] 
    mov edi,esi    ;edi pointer to first character also 
    cld 
    @@countloop: 
    lodsb 
    cmp al,0 
    jne SHORT @@countloop 
    dec esi     ;we're now pointing past NULL, so back up one 
    sub esi,edi    ;subtract beginning pointer from pointer at NULL so that esi now contains string count 

    ;return string length in returned in eax 
    mov eax,esi 

    ret 
getStringLength ENDP 

; 
; outputString(pszString) - outputs a zero terminated string 
; returns 0 on failure or final character count upon success (excluding NULL terminator) 
; 
outputString PROC STDCALL 
    LOCALS 
    ARG hConsole:DWORD 
    ARG pszString:DWORD 
    LOCAL dwCharsWrote:DWORD 

    ;get string length (in eax) 
    lea esi,pszString 
    mov esi,[esi] 
    call getStringLength ,esi 

    ;load string pointer into esi 
    lea esi,pszString 
    mov esi,[esi] 

    ;load dwCharsWrote pointer into edx 
    lea edx,dwCharsWrote 

    ;write string to console 
    call WriteConsoleA ,hConsole,edi,eax,edx,NULL 

    ;if the function fails, return 0, otherwise return the characters written 
    cmp eax,0 
    jz @@funcdone 
    mov eax,[dwCharsWrote] 
    @@funcdone: 
    ret 
outputString ENDP ;outputString() 

; 
; numToString() - converts unsigned DWORD to digit string 
; 
numToString PROC STDCALL 
    ARG uNum:DWORD 
    ARG uBase:DWORD 
    ARG pDest:DWORD 
    ARG uDestLen:DWORD 
    ARG bSigned:DWORD 
    LOCAL pEnd:DWORD 
    LOCAL bHasSign:DWORD 

    ;default to number not signed 
    mov [bHasSign],0 

    ;if we're interpreting number as signed, see if 32nd bit (sign flag) is set 
    cmp bSigned,0 
    jz SHORT @@setup_div_loop 
    test DWORD PTR [uNum],080000000h 
    jz SHORT @@setup_div_loop 
    mov [bHasSign],1 ;number is signed: set sign flag, then remove the sign 
    not [uNum]   ; from the bits VIA: bitwise NOT, then adding 1 
    inc [uNum]   ; this will give us an unsigned representation of the same number 
         ; for which we will add a negative sign character at end 

    ;setup divide/remainder loop 
    @@setup_div_loop: 
    mov edi,[pDest]  ;edi points to beginning of dest buffer 

    mov ebx,edi   ;pEnd variable will point 1 past end of buffer 
    add ebx,[uDestLen] 
    mov [pEnd],ebx 

    mov ebx,[uBase]  ;ebx will hold the base to convert to 

    mov eax,uNum   ;eax is our number to convert 

    @@divloop: 
    ;range check buffer 
    cmp edi,[pEnd]   ;if we are we outside of buffer? 
    jae SHORT @@errorbufoverflow ; we've overflowed 

    ;setup 32-bit divide - divide eax by radix (ebx) 
    xor edx,edx 
    div ebx 

    ;assume remainder can always fit in byte (should range check radix) 
    ; and convert value to ASCII (values past 9 get hex digits 
    cmp dl,9 
    ja SHORT @@convletters 
    add dl,48    ;convert 0-9 to ASCII digits 
    jmp SHORT @@chardone 
    @@convletters: 
    add dl,55    ;convert A-F (letter A starts at 65, and we want to back it up by 10 to 55 such that 65 is for the value 10) 
    @@chardone: 
    mov BYTE PTR [edi],dl ;remainder goes in buffer 
    inc edi    ;point at next character 
    cmp eax,0    ;if quotient nonzero, keep dividing 
    jnz SHORT @@divloop 

    ; 
    ; loop above complete 
    ; 

    ;do we need to add sign? 
    cmp [bHasSign],0 
    jz SHORT @@nullTerminate 
    ; yes, range check that we have room 
    cmp edi,[pEnd] 
    jae SHORT @@errorbufoverflow 
    ; we have room, add sign character to string 
    mov BYTE PTR [edi],'-' 
    inc edi 

    @@nullTerminate: 
    ;range check buffer that we can NULL terminate the string 
    cmp edi,[pEnd] 
    jae SHORT @@errorbufoverflow  
    mov BYTE PTR [edi],0   ;SUCCESS - NULL terminate 

    ;return character count in eax (not counting null) 
    mov eax,edi   ;subtract start of buffer 
    sub eax,[pDest]  ; from ending position of buffer to obtain count 

    ; 
    ; we now have correct numeric string, but with least significant digits first 
    ; we must reverse the string to make it human-readible 
    ; 
    mov esi,[pDest] ;esi is left pointer 
    dec edi   ;edi is right pointer 
    @@reverseloop: 
    cmp esi,edi 
    jae SHORT @@procdone ;if esi ever meets or goes past edi, we're done! 

    mov dl,BYTE PTR [esi] ;swap esi and edi bytes 
    xchg dl,BYTE PTR [edi] 
    mov BYTE PTR [esi],dl 

    dec edi 
    inc esi 
    jmp SHORT @@reverseloop  

    @@errorbufoverflow: 
    ;ERROR: buffer length too small 
    mov eax,CODE_ERROR_BUFLEN 

    @@procdone: 
    ret 
numToString ENDP 

; 
; appMain() 
; 
appMain PROC STDCALL 
    LOCAL hConsole:DWORD 
    LOCAL szCode[MAXLEN_BINARYNUM_BUFFER_AS_DWORD]:DWORD 

    ;get handle to console 
    call GetStdHandle ,STD_OUTPUT_HANDLE 
    mov hConsole,eax 

    ;output message 
    call outputString ,hConsole,OFFSET szMsg 

    ;this is your negative value 
    mov eax,-352 

    ;convert value to string 
    lea esi,[szCode] 
    call numToString ,eax,10,esi,MAXLEN_BINARYNUM_BUFFER,1 

    ;output number buffer 
    lea esi,[szCode] 
    call outputString ,hConsole,esi 
    ret 
appMain ENDP 

; 
; Program Entry Point 
; 
_start: 
    call appMain 
    call ExitProcess ,eax 
end _start 
Смежные вопросы