汇编 - 无法检查字符串中的非数字

时间:2014-09-03 12:37:15

标签: string delphi assembly

我试图创建一个循环字符串的简单程序,如果任何字符不在字符0-9中,则递增寄存器。

没有语法错误或任何内容,但输出是零星的,每次运行时都会更改。所以基本上,它不起作用,因为它没有输出预期的结果。

我正在使用' asm' Delphi的功能是写这个,所以变量是在ASM代码之外定义的。

这是我的代码:

function checkInteger(numIn : String) : Boolean;
var isValid : Boolean;
  lengthOfString,incorrectCharacters,count: integer;
  buffer: integer;
begin

lengthOfString := length(numIn);
buffer := 0;

//BEGIN ASSEMBLY

asm
    xor edx,edx
    lea ecx,[numIn]
    mov [count],ecx

    @next:
    mov ecx,[count]
    movzx eax,byte[ecx]


    inc ecx
    mov [count],ecx

    cmp eax,'0'
    jb @increase_incorrect
    cmp eax,'9'
    ja @increase_incorrect

    jmp @skip

    @increase_incorrect:
    inc edx

    @skip:

    mov ecx,[lengthOfString]
    sub ecx,1
    mov [lengthOfString],ecx
    cmp ecx,0
    jg @next
    mov [incorrectCharacters],edx

end;

//END ASSEMBLY

if(incorrectCharacters > 0) then begin
  isValid := true;
end else begin
  isValid := false;
end;

checkInteger := isValid;
end;

' numIn'变量只是用户输入的包含任何有效字符的字符串。作为一个注释,当我在程序的早期检查时,字符串永远不会为空。

2 个答案:

答案 0 :(得分:2)

马上,这是错误的:

lea ecx,[numIn]

将局部变量numIn的地址加载到esi寄存器中。但是你想要缓冲区的地址。

mov ecx,numIn

当然,您需要添加一些代码来处理空字符串,numInnil if(incorrectCharacters > 0) then begin isValid := true; end else begin isValid := false; end; checkInteger := isValid;

我认为将Pascal和asm混合在一个函数中是有问题的。编译器不知道你的asm代码对寄存器做了什么,反之亦然。不要把Pascal和asm混合在一起。


我想知道这段代码试图实现的目标:

checkInteger := incorrectCharacters > 0;

不是吗?

isValid

执行此操作并删除function checkInteger(const numIn : AnsiString) : Boolean; var i: Integer; begin for i := 1 to Length(numIn) do if (numIn[i]<'0') or (numIn[i]>'9') then begin Result := False; exit; end; Result := True; end; 变量。


如果您希望代码运行良好,则应在找到一个无效字符后立即退出。计算有多少是毫无意义的。一旦你找到了,你需要摆脱困境。

我这样写:

{{1}}

编译器将其转换为以下内容:

0041A150 56               push esi
0041A151 8BF0             mov esi,eax
0041A153 8BD6             mov edx,esi
0041A155 85D2             test edx,edx
0041A157 7405             jz $0041a15e
0041A159 83EA04           sub edx,$04
0041A15C 8B12             mov edx,[edx]
0041A15E 8BCA             mov ecx,edx
0041A160 85C9             test ecx,ecx
0041A162 7E1A             jle $0041a17e
0041A164 BA01000000       mov edx,$00000001
0041A169 0FB64416FF       movzx eax,[esi+edx-$01]
0041A16E 3C30             cmp al,$30
0041A170 7204             jb $0041a176
0041A172 3C39             cmp al,$39
0041A174 7604             jbe $0041a17a
0041A176 33C0             xor eax,eax
0041A178 5E               pop esi
0041A179 C3               ret 

这比你管理的要好得多。一个很好的练习就是从这里开始并尝试改进它。

答案 1 :(得分:1)

我决定抛出我的解决方案,充分利用ESI寄存器:

function HasNonDigits(const S: AnsiString): Boolean;
asm
        push    esi

        { ecx <- LStrLen(S) }
        mov     ecx, dword ptr [S-4]

        lea     esi, [S]
        cld               { for illustrative purpose, see the note }
@loop:
        lodsb             { al <- [esi]; esi <- esi+1; ecx <- ecx-1 }
        cmp     al, '0'
        jl      @true
        cmp     al, '9'
        jg      @true
        loop    @loop

        mov     al, 0     { Ord(False) } 
        jmp     @endp

@true:
        mov     al, 1     { Ord(True) }
@endp:
        pop     esi
end;

procedure TForm1.FormCreate(Sender: TObject);
const
  Tests: array[0..5] of AnsiString = (
    '12345',
    'foo',
    '700',
    'barbar',
    'streisand',
    'f33r'
  );
var
  I: Integer;
begin
  for I := Low(Tests) to High(Tests) do
    OutputDebugString(PChar(Format('%s -> %s', [
      Tests[I],
      BoolToStr(HasNonDigits(Tests[I]), True)
    ])));
end;

总结一下,内联汇编程序代码必须符合以下conventions

  

程序和功能必须保留EBX,ESI,EDI和EBP   寄存器,但可以修改EAX,EDX和ECX寄存器。什么时候   在汇编程序中实现构造函数或析构函数,请务必   保留DL寄存器。使用调用过程和函数   假设CPU的方向标志被清除(对应   到CLD指令)并且必须返回方向标志清除。