Вопрос по delphi – Как увеличить значение цикла FOR в операторе цикла FOR?

2

Я хочу знать, как увеличить значение в операторе цикла FOR.

Это мой код

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;

Ошибка: E2081 Присвоение переменной FOR-Loop 'i'.

Я пытаюсь перевести старый код из C # в Delphi, но я не могу увеличить "i". Увеличение & i; это не единственный путь, но я хочу знать, где проблема.

Ваш Ответ

6   ответов
1

Согласно Майку Саттону, вам нужен цикл while, а не цикл for.

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;

Delphi-реализация "для" оптимизирован, но в результате он менее гибок, чем стиль C

7

В дополнение к тому, что написал Лассе,assigning to a loop variable is generally considered a code smell, Это затрудняет чтение кода (если вы хотите преждевременно выйти из цикла, вы можете выразить это намного яснее, используя break / continue), и это часто делаетсяby accident, вызывая все виды неприятных побочных эффектов. Таким образом, вместо того, чтобы прыгать через обручи, чтобы компилятор не выполнял оптимизацию fu в любом цикле, где затрагивается переменная цикла, Borland (теперь CodeGear) укусил пулю и сделал присвоение переменной цикла недопустимым.

Если вы действительно хотите возиться с индексами цикла вручную, подумайте об использовании цикла while.

+1 Пока идет цикл с хорошо названной логической тестовой переменной. Тогда вы можете иметь счетчик, аналогичный исходному, но логическое тестовое значение включает в себя как пороговый тест для этого значения, так и одно или несколько других условий. Контроль цикла должен быть кристально чистым.
3

Если вам нужно изменить счетчик цикла внутри цикла, попробуйте использовать цикл while.

Кстати, вам нужен ваш     Результат: = True строка, которая будет первой строкой функции для правильной работы. Как это, он всегда будет возвращать True.

7

в этом случае вы можете просто сделать «продолжить»; вместо inc (i)

Чтобы уточнить далее, i увеличивается автоматически (часть конструкции for) в конце каждой итерации цикла for.
6

Конечно, остальные (в целом) правильны. То, что не было сказано, это то, что "я"; в вашей петлеdoesn't существовать. Delphi использует для этого регистр процессора. Вот почему вы не можете изменить его, и именно поэтому вы должны использовать «для». цикл (не "пока"), потому что "для"; это намного быстрее. Вот ваш код изменен (не проверен, но я думаю, что вы поняли идею) - также imho у вас было несколько ошибок - также исправил их:

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;

... также MemorySignature должно иметь «const» или 'var'. Иначе, как сейчас, массив копируется. Что означает замедление при каждом вызове «Check». Наличие «var» все происходит намного быстрее с неизменным кодом, потому что AFAIS MemorySignature не изменилась.

НТН

Выделение "я" регистр не означает, что он исчезает, он просто означает, что для него нет адреса. Я не понимаю акцента на оптимизации компилятора в ответах здесь. Оптимизация происходит потому, что язык запрещает определенное поведение, а не наоборот.
& APOS; & APOS конструкции; Это еще один вариант, который сочетает в себе преимущества двух выше. Это означает, что параметр перенесенby reference (следовательно, вызов очень быстрый), но параметр остается неизменным "снаружи". Это достигаетсяprohibiting «предварительное изменение»; компилятором во время компиляции. IOW этот параметрconstant (отсюда и название: «const») во всем теле функции. Пример: функция MyFunc (const a: строка); начать; а: = & APOS; Foo & APOS ;; конец; - когда вы пытаетесь скомпилировать это, компилятор выдаст ошибку вa:='Foo';  HTH (извините за мои большие комментарии :-))
& APOS; Перерыв & APOS; означает «Out of current LOOP». (для т. д.) в то время как «выход»; означает «Из текущего БЛОКА КОДА» quot; (процедура / функция и т. д.). В нашем конкретном случае, да,is то же самое, но (imho) - хороший навык кодирования для завершения функции на конечном «конце». Конечно, это общее правило, а не догма. Предположим, что кто-то другой берет код, и он решает, что после каждой проверки он должен стереть (IOW fill с # $ 00) MemorySignature, независимо от результата функции. Инстинктивно он "добавит" для " петля в конце. Если есть «Выход»; в середине, то этот кодsometimes пропущен
Есть несколько способов передачи параметров. Значение по умолчанию - по значению: s: = 'Foo & apos ;; MyFunc (ы); Написать (s); напишет «Foo»; независимо от того, что происходит внутри MyFunc, и это потому, что & s; это получитьcopied внутри функции (для защиты «внешних элементов» от изменений, происходящих внутри MyFunc) и если «s»; большой (много КБ), то это может быть дорого. Добавление «var» там означает, чтоonly указатель на «s»; (ссылка на 's') пропускается, что намного быстрее (всего несколько байтов), но это означает, что любые изменения, которые происходят внутри вашей функции, будут "видимыми". вне.
for абсолютно не гарантирует, что индексная переменная будет помещена в регистр (это должно быть очевидно хотя бы потому, что вы можете четко написать достаточно много вложенныхfor-переключается, что не хватает регистров для помещения переменных!). Более того, другие переменные могут (и являются) также вноситься оптимизаторами в регистры. Наконец, помещение переменной в регистр не влияет на ее изменчивость - регистры, очевидно, могут быть назначены точно так же, как и ячейки памяти. В целом, ужасное объяснение, которое может быть как фактически неверным, так и отвлекающим от реальной проблемы.
3

Проблема в том, что компилятор взял исходный код цикла FOR и предположил, что знает, что происходит, и, таким образом, он может оптимизировать код, выводя конкретные инструкции процессора, которые выполняются быстрее всего, с этими допущениями.

Если это позволило вам связываться со значением переменной, эти допущения могут выйти за пределы окна, и, следовательно, код может не работать, и поэтому он не позволяет вам изменить его.

Вместо этого вам нужно просто иметь отдельную переменную, которую вы фактически используете, и использовать только индексную переменную цикла FOR, чтобы отслеживать, сколько итераций вы выполнили в настоящее время.

Например, типичной оптимизацией может быть написание инструкций ЦП, которые прекратят итерацию, когда регистр индекса упадет до нуля, переписав цикл таким образом, что он будет вести внутренний отсчет, а не вверх, и если вы начнете возиться с переменная, он не мог переписать код таким образом.

@ Майкл: А также потому, что оригинальный Паскаль работал именно так.
Оптимизатору несложно увидеть, назначена ли переменная управления циклом в теле цикла. Похоже, что более вероятное назначение не позволяет легче понимать вещи - ради читателя-человека.

Похожие вопросы