dword比較を使用するコードは次のとおりです。
それは最初に文字列の長さをチェックすることに注意してください。これは、前述のライブラリでは文字列に長さのプレフィックスが付いているため、StrLenはインスタントO(1)であり、終了NULLのスキャンはフォールバックとしてのみ提供されます(この回答の2番目の部分を参照)。
実際の比較の前に長さを比較すると、さまざまな文字列の速度をO(1)にすることができます。これにより、大きな配列を検索する場合に、パフォーマンスが大幅に向上する可能性があります。
次に、比較はdwordsで行われ、最後に、文字列の長さが4の乗算でない場合、残りの1..3バイトがバイトごとに比較されます。
proc StrCompCase, .str1, .str2
begin
push eax ecx esi edi
mov eax, [.str1]
mov ecx, [.str2]
cmp eax, ecx
je .equal
test eax, eax
jz .noteq
test ecx, ecx
jz .noteq
stdcall StrLen, eax
push eax
stdcall StrLen, ecx
pop ecx
cmp eax, ecx
jne .noteq
stdcall StrPtr, [.str1]
mov esi,eax
stdcall StrPtr, [.str2]
mov edi,eax
mov eax, ecx
shr ecx, 2
repe cmpsd
jne .noteq
mov ecx, eax
and ecx, 3
repe cmpsb
jne .noteq
.equal:
stc
pop edi esi ecx eax
return
.noteq:
clc
pop edi esi ecx eax
return
endp
StrLenコードについて:
これがStrLenの実装です。
可能であれば、長さのプレフィックス付き文字列を使用していることがわかります。これにより、実行時間がO(1)になります。これが不可能な場合は、1サイクルあたり8バイトをチェックするスキャンアルゴリズムにフォールバックし、かなり高速ですが、それでもO(n)です。
proc StrLen, .hString ; proc StrLen [hString]
begin
mov eax, [.hString]
cmp eax, $c0000000
jb .pointer
stdcall StrPtr, eax
jc .error
mov eax, [eax+string.len]
clc
return
.error:
xor eax, eax
stc
return
.pointer:
push ecx edx esi edi
; align on dword
.byte1:
test eax, 3
jz .scan
cmp byte [eax], 0
je .found
inc eax
jmp .byte1
.scan:
mov ecx, [eax]
mov edx, [eax+4]
lea eax, [eax+8]
lea esi, [ecx-$01010101]
lea edi, [edx-$01010101]
not ecx
not edx
and esi, ecx
and edi, edx
and esi, $80808080
and edi, $80808080
or esi, edi
jz .scan
sub eax, 9
; byte 0 was found: so search by bytes.
.byteloop:
lea eax, [eax+1]
cmp byte [eax], 0
jne .byteloop
.found:
sub eax, [.hString]
clc
pop edi esi edx ecx
return
endp
ゼロで終了する文字列には、パフォーマンスとセキュリティの両方の問題があることに注意してください。
サイズのプレフィックス付き文字列を使用することをお勧めします。たとえば、前述のライブラリは動的文字列を使用します。この場合、文字列には、文字列の現在の長さを含むオフセット-4(上記のコードではstring.len)にdwordフィールドが含まれます。