The MASM Forum Archive 2004 to 2012

General Forums => The Campus => Topic started by: Nilrem on April 18, 2005, 08:38:37 AM

Title: String comparing issue
Post by: Nilrem on April 18, 2005, 08:38:37 AM
I'm trying to optimize my code (so getting rid of apis). I have a drop down menu and when I press a button it detects what has been selected.
This works perfectly fine with lstrcmp, offset lpDropDown, offset string
.if eax==0
code
.endif
code

I saw some other code lying around

mov      esi, offset string1
      mov      edi, offset string2
@@:
      mov      al,[esi]
      cmpsb
      jne      strings_not_equal
      test      al, al
      jne        @b
strings_are_equal:
      .....
strings_not_equal:
      .....
however this will not work because one of the strings, lpDropdown is not null terminated (well I don't think it is because I don't actually define it myself).
I then saw this for strings that aren't null terminated:
mov      esi, offset string1
      mov      edi, offset string2
      mov      ecx,string_length
      repz     cmpsb
      jne      strings_not_equal
strings_are_equal:
      .....
strings_not_equal:
      .....

however this doesn't work either, I think it is because one of the strings actually is null terminated. Though now looking at it in detail I think it is because only one string is a dword. I cannot change this though as one of them has to be declared as a byte otherwise I get an error compiling.
Thanks. I'm still learning I know but I want to stop relying on apis so much and optimize my code.
Title: Re: String comparing issue
Post by: thomasantony on April 18, 2005, 03:54:45 PM
Hi,
   AFAIK, you don't need to do mov al,[esi] if you are using cmpsb. I think

   mov al,[esi]
   cmp al,[edi]
   jne @blah

is faster than cmpsb. Then don't do test al,al. Instead, put length of one string in ecx and do

dec ecx
jnz @B   ; if more than 0 jump


Thomas
:U
Title: Re: String comparing issue
Post by: Nilrem on April 18, 2005, 11:13:12 PM

mov      eax, offset String21
      mov      edi, offset lpDropDown
      mov      ecx,7
      @@:
      cmp al, [edi]
      dec ecx
jnz @B   ; if more than 0 jump
      jne      @f

This isn't right obviously because it only compares the first byte. Could I use cmp al, [edi+ecx] or something to that effect?
Title: Re: String comparing issue
Post by: thomasantony on April 19, 2005, 05:31:03 AM
Oops,
    My mistake :red . You either do cmp al,[edi+ecx] or do an inc edi before the dec ecx

Thomas :U
Title: Re: String comparing issue
Post by: Nilrem on April 20, 2005, 08:06:46 AM
Doesn't work.
mov      eax, offset String21
      mov      edi, offset lpDropDown
      mov      ecx,7
      @@:
      cmp byte ptr al, [edi]
      jne      @f
      inc edi ; byte position
      inc eax ; byte position
      dec ecx ; counter
jnz @B   ; if more than 0 jump


For some reason when comparing the first byte al is 2A (which is an *) and edi is 4A which is J (what it should be). However both of the strings are the same. I did this in olly command bar
? al
and it showed this *J
did the same in edi and it had something like %\J
I'm not sure why this is happening or how to prevent it?
Title: Re: String comparing issue
Post by: hutch-- on April 20, 2005, 08:42:16 AM
Nilrem,

You only have 2 choices with astring compares with ANSI characters, either use TWO zero terminated strings to compare or set a length for the comparison and pass it to the procedure that does the comparison. Let us know what you have in mind and it can probably be fixed up easily enough.
Title: Re: String comparing issue
Post by: Nilrem on April 20, 2005, 08:48:48 AM
String21   db 'JongBot',0
that is one of the strings

However the other string is not declared it is just whatever is selected in the dropdownmenu (lpDropDown).
So I think that isn't zero terminated.
Thanks Hutch and Thomas for giving help. So that is what, the second option you said Hutch. 8-)
Title: Re: String comparing issue
Post by: thomasantony on April 20, 2005, 09:02:46 AM
Hi,
  If you get the string from a dropdown menu, it will be a zero terminated string

Thomas :U
Title: Re: String comparing issue
Post by: Nilrem on April 20, 2005, 09:25:35 AM
Ok I wonder why the code is not working then if they are both zero terminated (and of course it is since don't all windows api results end with a zero terminated string?).
Title: Re: String comparing issue
Post by: thomasantony on April 20, 2005, 10:45:58 AM
Why not use the szCmpi or szCmp functions in the MASM32 library?

Thomas :U
Title: Re: String comparing issue
Post by: hutch-- on April 20, 2005, 11:42:11 AM
Here is an algo to do sring compares based on a preset length.

LATER : Tweaked  :toothy


; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

strcmp proc str1:DWORD,str2:DWORD,cnt:DWORD

    push ebx
    push esi

    mov esi, str1       ; load 1st byte data in ESI
    mov edx, str2       ; load 2nd byte data in EDI
    mov eax, cnt        ; load byte count in EAX
    add esi, eax        ; add byte count to ESI
    add edx, eax        ; add byte count to EDI
    neg eax             ; reverse sign in EAX
    xor ebx, ebx        ; clear EBX to prevent stall with BL

  @@:
    mov bl, [esi+eax]   ; load byte at ESI into BL
    cmp bl, [edx+eax]   ; compare BL to byte in EDI
    jne @F              ; exit if not equal
    add eax, 1          ; add 1 to test next pair of bytes
    jnz @B              ; jump back if count is not zero

    mov eax, -1         ; non zero is matching strings
    jmp quit

  @@:
    xor eax, eax        ; zero is non matching strings

  quit:
    pop esi
    pop ebx

    ret

strcmp endp

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
Title: Re: String comparing issue
Post by: Nilrem on April 20, 2005, 03:14:00 PM
Haven't tested it yet. Some questions however. Why would bl stall? Why add eax,1 isn't inc eax quicker, or is that just preference?
Secondly since this post is about trying to optimize my code, I have several strings to compare, therefore how could I manipulate this easier, apart from putting strings into strings (for example string1 is always compared so move the next string, string2 into string1 using repnz or whatever it was I forgot) I'm asking this because I'm contemplating about a swicth statement but am unsure how to go about it. Thanks a lot in helping I really do appreciate it, maybe I am annoying but I really want to be a more efficient programmer. 8-)


Edit
Nevermind I see it's a procedure ready to use easily. However the questions still remain concerning efficieny and switch statements.
Basically I want to compare two strings (obviously) and then do something. At the moment I have the rather inefficient:


invoke lstrcmp, str1, str2 //str1 been dropdownmenu
.if eax==0
  code
.endif
invoke lstrcmp, str1, str2
.if eax==0
  code
.endif
invoke lstrcmp, str1, str2
.if eax==0
  code
.endif
You get the idea...


Edit again
I know you can't do this in asm, but I just remembered a project in Excel where using a V-lookup was incredibly useful, if that could be used that would be great. Just trying to prove I don't ask reams of questions without putting the effort in. 8-)
Title: Re: String comparing issue
Post by: AeroASM on April 20, 2005, 06:48:33 PM
inc and dec are slower on the P4 compared to add and sub. (I think)
Title: Re: String comparing issue
Post by: lingo on April 20, 2005, 10:46:59 PM
the same but shorter  :lol

strcmp proc str1:DWORD,str2:DWORD,cnt:DWORD
    push   esi
    mov    esi, str1   ; load 1st byte data in ESI
    mov    edx, str2   ; load 2nd byte data in EDI
    mov    eax, cnt    ; load byte count in EAX
LoopA:
    add    eax,-1
     jl    quit     
    movzx  ecx, byte ptr [esi+eax]   ; load byte at ESI into BL
    cmp    cl, [edx+eax]              ; compare BL to byte in EDI
     je    LoopA
    xor    eax, eax                   ; zero is non matching strings
quit:
    pop    esi
    ret
strcmp endp


Regards,
Lingo
Title: Re: String comparing issue
Post by: Nilrem on April 20, 2005, 11:40:02 PM
Thankyou. 8-) Had problems getting it to work. Hutch yours worked perfectly.
Title: Re: String comparing issue
Post by: hutch-- on April 21, 2005, 12:13:17 AM
Here is the same algo with the stack frame removed. It probably does not matter in this context but its easy enough to do and it appears to be working OK.

The algo is correctly binary compare rather than string compare and can be used for any memory comparison, not just string data.


; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

align 4

OPTION PROLOGUE:NONE
OPTION EPILOGUE:NONE

bytecmp proc txt1:DWORD,txt2:DWORD,cnt:DWORD

    push esi

    mov esi, [esp+8]    ; load 1st byte data in ESI
    mov edx, [esp+12]   ; load 2nd byte data in EDX
    mov eax, [esp+16]   ; load byte count in EAX
    add esi, eax        ; add byte count to ESI
    add edx, eax        ; add byte count to EDX
    neg eax             ; reverse sign in EAX
    xor ecx, ecx        ; clear ECX to prevent stall with CL

  align 4
  @@:
    mov cl, [esi+eax]   ; load byte at ESI into BL
    cmp cl, [edx+eax]   ; compare BL to byte in EDX
    jne @F              ; exit if not equal
    add eax, 1          ; add 1 to test next pair of bytes
    jnz @B              ; jump back if count is not zero

    sub eax, 1          ; non zero is matching strings
    jmp quit

  @@:
    xor eax, eax        ; zero is non matching strings

  quit:
    pop esi

    ret 12

bytecmp endp

OPTION PROLOGUE:PrologueDef
OPTION EPILOGUE:EpilogueDef

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

Title: Re: String comparing issue
Post by: lingo on April 21, 2005, 01:40:24 AM

"Thankyou.  Had problems getting it to work..."
Now is OK
Try again pls :bdg

Regards,
Lingo
Title: Re: String comparing issue
Post by: AeroASM on April 22, 2005, 08:24:32 PM
hey hutch:

If you want to negate a number, don't you have to use neg eax / add eax,1

instead of just neg eax?
Title: Re: String comparing issue
Post by: hutch-- on April 22, 2005, 11:50:35 PM
Aero,

Just write two examples and test it.
Title: Re: String comparing issue
Post by: AeroASM on April 23, 2005, 06:50:52 AM
Thats  weird. It worked in practice, but in thoery it does not work.

Consider half-byte signed numbers:

1111 = -1
1110 = -2
1101 = -3
1100 = -4
1011 = -5
1010 = -6
1001 = -7
1000 = -8
0111 = 7
0110 = 6
0101 = 5
0100 = 4
0011 = 3
0010 = 2
0001 = 1
0000 = 0

Take 5 = 0101
neg eax gives 1010 = -6
therefore neg eax \ add eax,1 gives -6 + 1 = -5
Title: Re: String comparing issue
Post by: tenkey on April 23, 2005, 04:00:29 PM
What theory?

Where did you get the idea that NEG of 0101 produces 1010 ?
Title: Re: String comparing issue
Post by: MichaelW on April 23, 2005, 05:13:43 PM
AeroASM,

I think you are confusing not and neg.

neg eax

would be functionally equivalent to

not eax
inc eax

Title: Re: String comparing issue
Post by: pbrennick on April 23, 2005, 05:21:41 PM
I think he forgot to do the twos compliment.

Paul
Title: Re: String comparing issue
Post by: AeroASM on April 23, 2005, 05:33:10 PM
MichaelW: spot on
pbrennick: wtf is twos complement?
Title: Re: String comparing issue
Post by: thomasantony on April 24, 2005, 08:17:07 AM
Quote from: AeroASM on April 23, 2005, 05:33:10 PM
MichaelW: spot on
pbrennick: wtf is twos complement?
Yeah,
  I was thinking of asking that. I have seen both one's complement and two's complement and they have complemented my mind :wink

Thomas :U
Title: Re: String comparing issue
Post by: MichaelW on April 24, 2005, 08:56:15 AM
I posted this on the old forum, but it appears to have been lost.

Two's Complement
----------------
Processors of the x86 family use a two's complement representation
for signed integers. With this representation, the most significant
bit functions as a sign bit. A value of 0 for the sign bit indicates
a positive integer and a value of 1 indicates a negative integer.

For simplicity, the following examples use bytes, but the concept
is applicable to any size integer.

The value of a positive integer is the value of the bits:

   0000 0000b =  0
   0000 0001b = +1
   0000 0010b = +2
   ...
   0111 1111b = +127

The value of a negative integer is the value of the bits
minus 2^n, where n is the number of bits.

   1111 1111b (255) minus 2 ^ 8 (256) = -1
   1111 1110b (254) minus 2 ^ 8 (256) = -2
   1111 1101b (253) minus 2 ^ 8 (256) = -3
   ...
   1000 0000b (128) minus 2 ^ 8 (256) = -128

The next two examples require an understanding of the rules
for binary addition:

   0 + 0 = 0
   0 + 1 = 1
   1 + 0 = 1
   1 + 1 = 0 carry 1

To convert a value from positive to negative, or from negative
to positive, you invert (complement) all the bits and add 1:

   Start with +1:    0000 0001
   Invert all bits:  1111 1110
   Add 1:            0000 0001
   Now have -1:      1111 1111
   Invert all bits:  0000 0000
   Add 1:            0000 0001
   Now have +1:      0000 0001

You can verify that 1111 1111b represents -1 by adding 1:

   Start with -1:    1111 1111
   Add 1:            0000 0001
   Result is 0:    1 0000 0000 (carry ignored)


Title: Re: String comparing issue
Post by: AeroASM on April 24, 2005, 10:28:27 AM
Quote from: pbrennick on April 23, 2005, 05:21:41 PM
I think he forgot to do the twos compliment.

Paul


Thats what confused me. I knew that twos complement was a system of negative numbers, but I didn't know how to do a system.
Title: Re: String comparing issue
Post by: tenkey on April 25, 2005, 01:38:21 AM
Two's complement is also the name of an operation that creates the arithmetic negative in a two's complement system.
Title: Re: String comparing issue
Post by: AeroASM on April 25, 2005, 06:40:05 AM
OK, got it. When Pbrennick said I forgot to do the twos complement, he meant that I did not know that there is an opcode to do it.
Title: Re: String comparing issue
Post by: Nilrem on May 03, 2005, 04:30:43 PM
Hutch the problem arises if I have one string called Thunder and another Thunder2.
Title: Re: String comparing issue
Post by: hutch-- on May 03, 2005, 05:49:08 PM
Nilrem,

Quote
Hutch the problem arises if I have one string called Thunder and another Thunder2.

All tis means is the algo you are using is not doing the comparison properly for the string length. You only need to pass the length of one string, usually the first one and then do the comparison and you should pick if one is different in its last character than another.
Title: Re: String comparing issue
Post by: Nilrem on May 04, 2005, 02:36:16 PM
What I'm saying is I have the following

invoke strcmp, offset lpDropDown, offset ThunderPopper, 13

so if ThunderPopperII is selected from the dropdownmenu then when the above happens it will think ThunderPopper is selected when in fact ThunderPopperII is, but I cannot fix this problem because changing 13 to 15 results in if ThunderPopper is selected then it doesn't come up when it should.

I just either had to put strcmp ThunderPopperII before strcmp ThunderPopper
but I like it to be in order (my code) so instead I used szCmp.
Title: Re: String comparing issue
Post by: Mark Jones on May 04, 2005, 03:01:31 PM
Implement Hutch's idea. It would be great practice, plus be very fast.
Title: Re: String comparing issue
Post by: Nilrem on May 04, 2005, 03:20:04 PM
I have implemented his, but it doesn't work if I have this:


invoke strcmp, offset lpdropdown, offset thunderpopper, 13
jnz @f
ret
@@:
invoke strcmp, offset lpdropdown, offset thunderpopperII, 15
jnz @f
ret


That doesn't work if the string ThunderpopperII is selected because it stops at the first strcmp because the first 13 bytes of thunderpopperII matches the compare.
Title: Re: String comparing issue
Post by: tenkey on May 06, 2005, 05:07:59 AM
You need to pass the lengths of both strings. You need to know if the strings differ in length or not.
Title: Re: String comparing issue
Post by: hutch-- on May 06, 2005, 05:24:48 AM
There is something fundamentally wrong with the premises here, if the strings are zero terminated, it does not mater if they are the same up near the end or not, the difference is measured with the zero terminator included.


"string",0
"string1",0


A single coparison algo will exit when the "1" is compared with the terminating zero as a mismatch.
Title: Re: String comparing issue
Post by: Mark Jones on May 06, 2005, 08:05:02 AM
Check out this little snippet I made while up coding late. Very late. :)


SzComp  proc    sz1:DWORD, sz2:DWORD
    mov esi, sz1            ; load string offsets
    mov edi, sz2
    cld                     ; clear direction flag
@@:   
    cmpsb                   ; compare bytes esi,edi
    jne err                 ; different?
    cmp byte ptr [esi-1], 00  ; is one a null?   
    jz eos                  ; yes, strings match
    jmp @B
err:
    mov eax,1               ; compare failed
    ret
eos:
    mov eax,0               ; compare succeeded
    ret
SzComp endp
Title: Re: String comparing issue
Post by: Nilrem on May 06, 2005, 08:29:14 AM
Hutch what is wrong is ThunderPopper gets compared before ThunderPopperII

So if I have this

invoke strcmp, offset lpdropdown, offset thunderpopper, 13
jnz @f
code

@@:
invoke strcmp, offset lpdropdown, offset thunderpopperII, 15
jnz @f
code

As you can see if ThunderPopperII is in lpdropdown then at this point:

invoke strcmp, offset lpdropdown, offset thunderpopper, 13

only the first 13 bytes get compared and hence therefore it thinks ThunderPopper is in lpdropdown. What I should have done is tried and edited your algorithim you wrote Hutch so that when the comparison has finished, and it thinks it is successful I should then check to see if there is any remaining bytes, however whilst writing this I have realised that wouldn't work because I already specified 13 bytes. I think I'll look at szCmp and see the differences.
Mark Jones thanks for the late night coding effort, I'll try it later today hopefully.
Title: Re: String comparing issue
Post by: Mark Jones on May 06, 2005, 04:55:45 PM
Whoa nellie, my string compare is tons faster than lstrcmp, see the attached project:


SzCmp/lstrcmp speed comparison by Mark Jones (gzscuqn02ATsneakemailD0Tcom)
Timing routines by MichaelW from MASM32 forums: http://www.masmforum.com/
Please terminate any high-priority tasks and press ENTER to begin.

These are the three 64-byte strings being tested:
"Hello, this is an example of a MASM32 64-byte string comparison."
"Hello, this is an example of a MASM32 64-byte string comparison!"
"hello, this is an example of a MASM32 64-byte string comparison."

Timing results:

SzCmp, 64 bytes identical string: 416 clocks
SzCmp, 64 bytes different string (last character): 342 clocks
SzCmp, 64 bytes different string (first character): 11 clocks

lstrcmp, 64 bytes identical string: 1568 clocks
lstrcmp, 64 bytes different string (last character): 1619 clocks
lstrcmp, 64 bytes different string (first character): 2531 clocks

Press ENTER to exit...

[attachment deleted by admin]
Title: Re: String comparing issue
Post by: tenkey on May 06, 2005, 06:54:36 PM
Quote from: hutch-- on May 06, 2005, 05:24:48 AM
There is something fundamentally wrong with the premises here, if the strings are zero terminated, it does not mater if they are the same up near the end or not, the difference is measured with the zero terminator included.


"string",0
"string1",0


A single coparison algo will exit when the "1" is compared with the terminating zero as a mismatch.

Well, if indeed all the strings are 0-terminated, then the length to compare should include the terminator character. In other words, one more than the number of significant (or "interesting") characters.
Title: Re: String comparing issue
Post by: AeroASM on May 06, 2005, 07:11:19 PM
Well, if indeed all the strings are 0-terminates, then you don't need a length.
Title: Re: String comparing issue
Post by: tenkey on May 06, 2005, 07:57:46 PM
That's true, but the length is being used for optimizing speed.
Title: Re: String comparing issue
Post by: MichaelW on May 06, 2005, 08:21:47 PM
Hi Mark,

Interesting! What were you running on? These are my results running on a P3:

SzCmp/lstrcmp speed comparison by Mark Jones (gzscuqn02ATsneakemailD0Tcom)
Timing routines by MichaelW from MASM32 forums: http://www.masmforum.com/
Please terminate any high-priority tasks and press ENTER to begin.

These are the three 64-byte strings being tested:
"Hello, this is an example of a MASM32 64-byte string comparison."
"Hello, this is an example of a MASM32 64-byte string comparison!"
"hello, this is an example of a MASM32 64-byte string comparison."

Timing results:

SzCmp, 64 bytes identical string: 402 clocks
SzCmp, 64 bytes different string (last character): 391 clocks
SzCmp, 64 bytes different string (first character): 18 clocks

lstrcmp, 64 bytes identical string: 372 clocks
lstrcmp, 64 bytes different string (last character): 967 clocks
lstrcmp, 64 bytes different string (first character): 3296 clocks

Title: Re: String comparing issue
Post by: Mark Jones on May 06, 2005, 09:40:54 PM
Michael, my results were with an AMD XP 1800+. Those are some pretty big differences. :)
Title: Re: String comparing issue
Post by: roticv on May 07, 2005, 01:37:56 PM
Your P3 seem to be faster than my Celeron 2.4ghz  :toothy

Timing results:

SzCmp, 64 bytes identical string: 903 clocks
SzCmp, 64 bytes different string (last character): 888 clocks
SzCmp, 64 bytes different string (first character): 49 clocks

lstrcmp, 64 bytes identical string: 2209 clocks
lstrcmp, 64 bytes different string (last character): 2297 clocks
lstrcmp, 64 bytes different string (first character): 3097 clocks


I think string opcodes are worse on newer computers.
Title: Re: String comparing issue
Post by: Nilrem on May 07, 2005, 01:46:04 PM
No, just Celeron is slower. My P3 850Mhz loads games faster then a Celeron 2GHz. 8-)
Title: Re: String comparing issue
Post by: thomasantony on May 07, 2005, 02:38:46 PM
Hi Nilrem, Seems like we have the same processor.

Thomas :U
Title: Re: String comparing issue
Post by: Nilrem on May 07, 2005, 03:24:36 PM
Hehe, well I really need an upgrade for the new games, anyways let's not take the topic off-topic. Please check your pm Thomas.