I needed a 32-bit integer to ascii conversion procedure that could handle multiple bases (2, 10, and 16) for a 16-bit project, so I duplicated the base range for the CRT itoa function (2-36), and did this 32-bit version to get the code working and test it:
;==============================================================================
include \masm32\include\masm32rt.inc
include \masm32\macros\timers.asm
.686
;==============================================================================
.data
buff1 db 100 dup(0)
buff2 db 100 dup(0)
.code
;==============================================================================
.data
dwtoa_base_digits db "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
.code
dwtoa_base proc src:DWORD, pbuff:DWORD, base:DWORD
push ebx
push edi
mov eax, src
mov edi, pbuff
cmp base, 10
jne @F
test eax, eax
jns @F
neg eax
mov BYTE PTR [edi], '-'
inc edi
@@:
mov ebx, base
xor ecx, ecx
@@:
cdq
div ebx
push edx
inc ecx
test eax, eax
jnz @B
@@:
pop eax
mov dl, dwtoa_base_digits[eax]
mov [edi], dl
inc edi
dec ecx
jnz @B
pop edi
pop ebx
ret
dwtoa_base endp
;==============================================================================
start:
;==============================================================================
printf("base 10 negative values\n")
xor ebx, ebx
.WHILE SDWORD PTR ebx > -1000000
invoke dwtoa_base, ebx, ADDR buff1, 10
invoke crt__itoa, ebx, ADDR buff2, 10
invoke crt__stricmp, ADDR buff1, ADDR buff2
invoke RtlZeroMemory, ADDR buff1, SIZEOF buff1
invoke RtlZeroMemory, ADDR buff2, SIZEOF buff2
test eax, eax
jz @F
printf("%s\t%s\n", ADDR buff1, ADDR buff2)
@@:
dec ebx
.ENDW
FOR base,<2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,36>
printf("base %d\n", base)
xor ebx, ebx
.WHILE ebx < 1000000
invoke dwtoa_base, ebx, ADDR buff1, base
invoke crt__itoa, ebx, ADDR buff2, base
invoke crt__stricmp, ADDR buff1, ADDR buff2
invoke RtlZeroMemory, ADDR buff1, SIZEOF buff1
invoke RtlZeroMemory, ADDR buff2, SIZEOF buff2
test eax, eax
jz @F
printf("%s\t%s\n", ADDR buff1, ADDR buff2)
@@:
inc ebx
.ENDW
ENDM
printf("\n")
invoke GetCurrentProcess
invoke SetProcessAffinityMask, eax, 1
invoke Sleep, 5000
REPEAT 4
counter_begin 1000000, HIGH_PRIORITY_CLASS
counter_end
printf("%d cycles\n", eax)
counter_begin 1000000, HIGH_PRIORITY_CLASS
invoke dwtoa_base, 123456789, ADDR buff1, 10
counter_end
printf("%d cycles\n", eax)
counter_begin 1000000, HIGH_PRIORITY_CLASS
invoke crt__itoa, 123456789, ADDR buff2, 10
counter_end
printf("%d cycles\n\n", eax)
ENDM
inkey
exit
;==============================================================================
end start
For my application the conversion speed, within reason, does not matter so I used simple, straightforward code, and was somewhat surprised that it is faster than the CRT function, at least when running on my P3.
base 10 negative values
base 2
base 3
base 4
base 5
base 6
base 7
base 8
base 9
base 10
base 11
base 12
base 13
base 14
base 15
base 16
base 36
0 cycles
429 cycles
443 cycles
0 cycles
429 cycles
443 cycles
0 cycles
429 cycles
443 cycles
0 cycles
429 cycles
443 cycles