tasm
Display Negative numbers in TASM
How can I print a negative number in tasm? Please anyone help me. For e.g If I do a subtraction 2-7=(-5). How can I print -5?
You will need to perform the number conversion yourself (e.g. such as with your own function). I threw this TASM5 compatible Win32 app together as an example although I'm sure you can find countless other number->string conversion samples online. This might seem like a lot of code for such a simple goal however if you place "common" functions that are designed to be generic enough to be used in any number of programs in an include file or library, the real program is only the appMain() function at the bottom which is only about 10 lines of code. I threw everything in one file for purposes of being a complete working example. You are interested in the numToString() function shown below which converts a DWORD to a number within a buffer passed to the function. The rest of the code is just a framework to call the function along with some common WriteConsole wrappers. numToString() supports converting numbers to any base (such as hex and binary). In this example, I pass arguments to specify base-10 with the negative flag enabled (indicating to treat the DWORD number as signed). The algorithm for numToString() is as follows: -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. Program Output: The number is: -352 Program Listing: .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
Related Links
How do you code subtraction in TASM
How to do inverse subtraction in TASM?
Display Negative numbers in TASM
getch() in TASM
why do we use 0dh,0ah after msg1 db in this statement :msg1 db 0dh, 0ah, “ENTER A CHOICE $”;
TASM problems with output
TASM Can't locate .asm file Error: **Fatal** Command line: Can't locate file: filename.asm
TASM giving no output after compile
I can't figure out how to delete a row in my tasm assembly homework
How to read and write A FAT in WinXP [duplicate]
Turbo Assembler [closed]
8086 programming using TASM: pc to pc communication