问题
I want to know how to increase the value in a FOR-loop statement.
This is my code.
function Check(var MemoryData:Array of byte;MemorySignature:Array of byte;Position:integer):boolean;
var i:byte;
begin
for i := 0 to Length(MemorySignature) - 1 do
begin
while(MemorySignature[i] = $FF) do inc(i); //<< ERROR <<
if(memorydata[i + position] <> MemorySignature[i]) then Result:=false;
end;
Result := True;
end;
The error is: E2081 Assignment to FOR-Loop variable 'i'.
I'm trying to translate an old code from C# to Delphi,but I can't increase 'i'. Increasing 'i' is not the only way to go,but I want to know where the problem is.
回答1:
Of course the others are (generally) correct. What wasn't said, is that 'i' in your loop doesn't exist. Delphi uses a CPU register for it. That's why you cannot change it and that's why you should use a 'for' loop (not a 'while') because the 'for' is way faster. Here is your code modified (not tested but I think that you got the idea) - also imho you had some bugs - fixed them also:
function Check(var MemoryData:Array of byte;MemorySignature:Array of byte;Position:integer):boolean;
var i:byte;
begin
Result := True; //moved at top. Your function always returned 'True'. This is what you wanted?
for i := 0 to Length(MemorySignature) - 1 do //are you sure??? Perhaps you want High(MemorySignature) here...
begin
if MemorySignature[i] <> $FF then //speedup - '<>' evaluates faster than '='
begin
Result:=memorydata[i + position] <> MemorySignature[i]; //speedup.
if not Result then
Break; //added this! - speedup. We already know the result. So, no need to scan till end.
end;
end;
end;
...also MemorySignature should have a 'const' or 'var'. Otherwise as it is now the array gets copied. Which means slowdown at each call of 'Check'. Having a 'var' the things are much faster with code unchanged because AFAIS the MemorySignature isn't changed.
HTH
回答2:
in this case, you can just do a 'continue' instead of inc(i)
回答3:
In addition to what Lasse wrote, assigning to a loop variable is generally considered a code smell. It makes code harder to read (if you want to leave the loop premataturely, you can express that a lot clearer using break/continue), and is often done by accident, causing all kind of nasty side-effects. So instead of jumping through hoops to make the compiler not do its optimizing fu on any loop where the loop variable is touched, Borland (now CodeGear) bit the bullet and made assigning to the loop variable illegal.
If you really want to mess about manually with loop indices, consider using a while-loop.
回答4:
If you need to alter a loop counter inside a loop, try using a while loop instead.
BTW, you need your Result := True line to be the first line of the function for it to work properly. As it is, it will always return True.
回答5:
The problem is that the compiler has taken the original FOR-loop code and assumed it knows what is happening, and thus it can optimize the code by outputting specific CPU instructions that runs the fastest, with those assumptions.
If it allowed you to mess with the variable value, those assumptions might go out the window, and thus the code might not work, and that's why it doesn't allow you to change it.
What you should do instead is just have a separate variable that you're actually using, and only use the FOR-loop indexing variable to keep track of how many iterations you've currently executed.
As an example, a typical optimization might be to write CPU-instructions that will stop iterating when the index register drops to zero, rewriting the loop in such a way that it internally counts down, instead of up, and if you start messing with the variable, it could not rewrite the code like that.
回答6:
As per Mike Sutton, what you need is a while loop, not a for loop.
function Check(var MemoryData: Array of byte;
MemorySignature: Array of byte; Position: Integer):Boolean;
var
i:byte;
begin
Result := True;
i := 0;
while i < Length(MemorySignature) do
begin
while(MemorySignature[i] = $FF) do
Inc(i);
if(MemoryData[i + position] <> MemorySignature[i]) then
Result := False;
Inc(i);
end;
end;
The Delphi implementation of "for" is optimised, but as a result it is less flexible than the C-style
来源:https://stackoverflow.com/questions/1105519/how-to-increase-the-for-loop-value-in-a-for-loop-statement