How to convert a DWORD into a DB

2019-09-14 01:36发布

问题:

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.

回答1:

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".



回答2:

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