Hello,
Further to my thread about why you'd want to convert a string to a DWord, can someone explain how it is done please?
The procedure below is taken from one of the tutorials, it'd be great if someone could comment it for me.
Thanks in advance,
~Adam


String2Dword proc uses ecx edi edx esi String:DWORD
LOCAL Result:DWORD

mov Result,0
mov edi,String
invoke lstrlen, String
.WHILE eax!=0
xor edx,edx
mov dl,byte ptr
sub dl,"0"
mov esi,eax
dec esi
push eax
mov eax,edx
push ebx
mov ebx,10
.WHILE esi > 0
mul ebx
dec esi
.ENDW
pop ebx
add Result,eax
pop eax
inc edi
dec eax
.ENDW
mov eax,Result
ret
String2Dword endp
Posted on 2002-09-12 12:27:37 by adamjjackson
Here's a quick string to int converter. It reads the string and returns the
value in eax. This should be simpler than the version you posted and easier
to understand. Note that it does not check for bytes that are out of range
(ie., it doesn't verify that the digit is indeed a digit and not a letter
or punctuation)



StrToInt PROC uses edi edx lpString:DWORD
mov edi,lpString ;Load edi with the address of the string
xor eax,eax ;clear eax to zero
xor edx,edx ;clear edx too
@@:
mov dl,BYTE PTR [edi] ;read a byte from the string
test dl,dl ;is it a zero byte? i.e., are we done?
jz @@Exit ;if so, jump to the exit
imul eax,10 ;multiply the current value in eax by 10
sub dl,"0" ;shift the ascii value to an integer
add eax,edx ;add the integer to our running total in eax
inc edi ;point to the next byte
jmp @B ;loop
@Exit:
ret ;exit
StrToInt ENDP


There are a couple of things to note:
1) when you read an ascii digit, you must do sub dl,"0" to get the actual
integer value. Check out an ascii table and you'll see what I mean
2) you can replace sub dl,"0"/add eax,edx with lea eax, if you like
3) we are done when we encounter a zero byte in the string (that is, the
string should be null-terminated)

--Chorus
Posted on 2002-09-12 12:44:46 by chorus
This might be a faster version of:


test dl,dl ;is it a zero byte? i.e., are we done?
jz @@Exit ;if so, jump to the exit
imul eax,10 ;multiply the current value in eax by 10
sub dl,"0" ;shift the ascii value to an integer
add eax,edx ;add the integer to our running total in eax




or edx,0
jz @@Exit
and edx, 0xF
add eax, edx
add eax, edx
shl edx, 3
add eax, edx
Posted on 2002-09-12 22:35:58 by eet_1024
Or you could use ATODW from MASM32.LIB, and DWTOA to convert them back. Pretty easy "built in" way to do it.

I made one called DWTOAE that inserts commas in the result string... :cool:
Posted on 2002-09-13 00:34:13 by S/390
Yes, IIRC there were also many posts about this in the Algorithm section with optimized code snippets...
The search feature will probably return them...
Posted on 2002-09-13 01:21:39 by JCP
Howdy,
Sorry for my ignorance! But can you explain why you need to multiply by 10? I don't understand that bit, and it all seems to hinge on it!
Thanks again,
~Adam
Posted on 2002-09-13 04:49:05 by adamjjackson
Think about it like this: in writing a regular base 10 number, like 3431, each digit stands for a power of 10. So we read "3431" as meaning the number 3*1000+4*100+3*10+1.
The algo works like this:

start with nothing.
grab the first digit (3)
add it to what you've got (0+3=3)
multiply by 10 cause we're gonna grab the next digit(3*10=30)
grab the next digit (4)
add it to what you've got (30+4=34)
multiply by 10 (34*10=340)
grab the next digit (3)
add it to what you've got (340+3=343)
multiply by 10 (343*10=3430)
grab the next digit (1)
add it to what you've got (3430+1=3431)

By looping like this, we automatically multiply each digit by the right power of 10

--Chorus
Posted on 2002-09-13 06:41:04 by chorus
eet_1024:
you have the right idea, but I think you swapped eax and edx. You don't want to multiply edx by 10, but eax.
also, iirc, test should be "faster" than or ever so slightly because it won't generate the uop to write the result back to the register.
and ideally, you could drop the and edx,0Fh because there is an xor edx,edx done at the beginning and we never touch edx except to move a byte in to dl

--Chorus
Posted on 2002-09-13 06:45:42 by chorus
You guys are making this difficult. :)

You divide by 10 because you're converting to decimal, or base 10. The remainder of each divide will be a decimal value. ie. between 0 and 9.

Pick a number, like 3107. Forget the base, just concentrate on the number.

Divide 3107 by 10, answer 310 remainder -> 7

Divide 310 by 10, answer 31 remainder --> 0

Divide by 31 by 10, answer 3, remainder ---> 1

Divide 3 by 10, answer 0, remainder ----> 3

Easy, huh? :grin:

Oops, forgot the last part... This is how you convert back to s string. Now, just do the opposite...
Posted on 2002-09-13 12:29:31 by S/390
chorus,
You're right, I did swap them (cuz I was thinking backwards). I used and edx, 0xF to replace the sub edx, 0x30.

S/390,
Multiply is faster than Divide. Shift is much faster than Multiply (for integers with simple binary decompositions).

adamjjackson,
When you take 3*1000+4*100+3*10+1*1 and do the math in a different base, it has the side effect of 'converting' it to that base.
3*3E8+4*64+3*A+1*1 = 0xD67

It also works the other way. I'll use square brackets to denote the place values:
   [6][7] base 16 = [13][6][7] base 10
So we now have (in base 10):
   13*256+ 6*16 + 7*1 = 3431
Notice that I'm using powers of 16.

Repeated division and modulos give the same result
Posted on 2002-09-14 01:19:06 by eet_1024

I used and edx, 0xF to replace the sub edx, 0x30.


Ahh... I see now. Nice trick :)

--Chorus
Posted on 2002-09-14 08:06:17 by chorus