Hello,

Further to my thread about why you'd want to convert a string to a DWord, can someone explain how it is done

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

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

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)

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

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

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

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:

I made one called DWTOAE that inserts commas in the result string... :cool:

Yes, IIRC there were also many posts about this in the Algorithm section with optimized code snippets...

The search feature will probably return them...

The search feature will probably return them...

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

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

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

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

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

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

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

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

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

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

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

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

--Chorus