I want to display a score in a game that I built in MASM32, and I have a problem, how do I convert a DWORD to a DB (string).
There is the function crt__itoa
to convert a dword to an integer , but for some reason it doesn't work (do i need to include an other lib ? ).
There is the function TextOutA to display a score, but again I cant print it out because I don't have a string so it can print it from.
do i need to include an other lib? - Probably. You need msvcrt.inc
and msvcrt.lib
for crt__itoa
.
masm32rt.inc
is the Swiss Army Knife for such cases. Here is a working example:
include c:\masm32\include\masm32rt.inc
.DATA
fmt db "%s",10,0
num dd 1234567
num_str db 16 dup (?)
.CODE
main PROC
; with CALL:
push 10
push OFFSET num_str
push num
call crt__itoa
add esp, 12
push OFFSET num_str
push OFFSET fmt
call crt_printf
add esp, 8
; or with INVOKE:
invoke crt__itoa, num, OFFSET num_str, 10
invoke crt_printf, OFFSET fmt, OFFSET num_str
invoke ExitProcess, 0
main ENDP
END main
The program does not stop. If you don't call it in an extra command prompt window it will open a window and close it immediately. In Qeditor
I suggest to insert a line "Run & Pause" into menus.ini
:
...
&Run Program,"{b}.exe"
Run && Pause,cmd.exe /C"{b}.exe" & pause
...
Now you have a new item under "Project".
Next is a method made with Visual Studio 2010 C++ that manually converts EAX into a string (it doesn't need any library, just copy-paste and use). It takes a number as parameter, assign it to EAX, convert it to string and display the string :
void number2string ( int value ) {
char buf[11];
__asm { ;EXTRACT DIGITS ONE BY ONE AND PUSH THEM INTO STACK.
mov eax, value
mov ebx, 10 ;DIGITS ARE EXTRACTED DIVIDING BY 10.
mov cx, 0 ;COUNTER FOR EXTRACTED DIGITS.
cycle1:
mov edx, 0 ;NECESSARY TO DIVIDE BY EBX.
div ebx ;EDX:EAX / 10 = EAX:QUOTIENT EDX:REMAINDER.
push dx ;PRESERVE DIGIT EXTRACTED (DL) FOR LATER.
inc cx ;INCREASE COUNTER FOR EVERY DIGIT EXTRACTED.
cmp eax, 0 ;IF NUMBER IS
jne cycle1 ;NOT ZERO, LOOP.
;NOW RETRIEVE PUSHED DIGITS IN REVERSE ORDER.
mov esi, 0 ;POINTER TO STRING'S CHARACTERS.
cycle2:
pop dx ;GET A DIGIT.
add dl, 48 ;CONVERT DIGIT TO CHARACTER.
mov buf[ esi ], dl
inc esi ;NEXT POSITION IN STRING.
loop cycle2
mov buf[ esi ], 0 ;MAKE IT ASCIIZ STRING.
}
printf( buf );
scanf( "%s",buf ); // TO STOP PROGRAM AND LET US SEE RESULT.
}
Pay attention : previous method is a "void", so you call it as usual :
number2string( 1234567890 ); // CONVERT THIS BIG NUMBER IN STRING AND DISPLAY.
You can modify the method to return the string or to do anything you want.
Now (for those who are tough enough) the same previous procedure for pure assembler, made with GUI Turbo Assembler x64 (http://sourceforge.net/projects/guitasm8086/), this full program shows how it works :
.model small
.586
.stack 100h
.data
buf db 11 dup (?) ;STRING.
.code
start:
;INITIALIZE DATA SEGMENT.
mov ax, @data
mov ds, ax
;CONVERT EAX TO STRING.
call dollars ;FILL BUF WITH '$', NECESSARY TO DISPLAY.
mov eax, 1234567890
call number2string ;PARAMETER:EAX. RETURN:VARIABLE BUF.
;DISPLAY BUF (EAX CONVERTED TO STRING).
mov ah, 9
mov dx, offset buf
int 21h
;WAIT UNTIL USER PRESS ANY KEY.
mov ah, 7
int 21h
;FINISH PROGRAM.
mov ax, 4c00h
int 21h
;------------------------------------------
;NUMBER TO CONVERT MUST ENTER IN EAX.
;ALGORITHM : EXTRACT DIGITS ONE BY ONE, STORE
;THEM IN STACK, THEN EXTRACT THEM IN REVERSE
;ORDER TO CONSTRUCT STRING (BUF).
number2string proc
mov ebx, 10 ;DIGITS ARE EXTRACTED DIVIDING BY 10.
mov cx, 0 ;COUNTER FOR EXTRACTED DIGITS.
cycle1:
mov edx, 0 ;NECESSARY TO DIVIDE BY EBX.
div ebx ;EDX:EAX / 10 = EAX:QUOTIENT EDX:REMAINDER.
push dx ;PRESERVE DIGIT EXTRACTED (DL) FOR LATER.
inc cx ;INCREASE COUNTER FOR EVERY DIGIT EXTRACTED.
cmp eax, 0 ;IF NUMBER IS
jne cycle1 ;NOT ZERO, LOOP.
;NOW RETRIEVE PUSHED DIGITS.
mov si, offset buf
cycle2:
pop dx
add dl, 48 ;CONVERT DIGIT TO CHARACTER.
mov [ si ], dl
inc si
loop cycle2
ret
number2string endp
;------------------------------------------
;FILLS VARIABLE BUF WITH '$'.
;USED BEFORE CONVERT NUMBERS TO STRING, BECAUSE
;THE STRING WILL BE DISPLAYED.
dollars proc
mov si, offset buf
mov cx, 11
six_dollars:
mov bl, '$'
mov [ si ], bl
inc si
loop six_dollars
ret
dollars endp
end start