我试图创建一个循环字符串的简单程序,如果任何字符不在字符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'变量只是用户输入的包含任何有效字符的字符串。作为一个注释,当我在程序的早期检查时,字符串永远不会为空。
答案 0 :(得分:2)
马上,这是错误的:
lea ecx,[numIn]
将局部变量numIn
的地址加载到esi
寄存器中。但是你想要缓冲区的地址。
mov ecx,numIn
当然,您需要添加一些代码来处理空字符串,numIn
为nil
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指令)并且必须返回方向标志清除。