Тип условия, используемый в цикле, может ограничивать виды оптимизаций, которые может выполнять компилятор, к лучшему или к худшему. Например, учитывая:
uint16_t n = ...;
for (uint16_t i=1; i<=n; i++)
... [loop doesn't modify i]
компилятор может предположить, что вышеприведенное условие должно заставить цикл завершиться после цикла n-го прохода, если n не может 65535, и цикл может выйти каким-либо иным способом, кроме того, что i превысит n. Если эти условия применимы, компилятор должен сгенерировать код, который заставит цикл работать до тех пор, пока что-либо, кроме указанного выше условия, не заставит его завершиться.
Если цикл был записан как:
uint16_t n = ...;
for (uint16_t ctr=0; ctr<n; ctr++)
{
uint16_t i = ctr+1;
... [loop doesn't modify ctr]
}
тогда компилятор может с уверенностью предположить, что цикл никогда не должен будет выполняться более n раз и, таким образом, сможет генерировать более эффективный код.
Обратите внимание, что любое переполнение со знаком типов может иметь неприятные последствия. Данный:
int total=0;
int start,lim,mult; // Initialize values somehow...
for (int i=start; i<=lim; i++)
total+=i*mult;
Компилятор может переписать это как:
int total=0;
int start,lim,mult; // Initialize values somehow...
int loop_top = lim*mult;
for (int i=start; i<=loop_top; i+=mult)
total+=i;
Такой цикл будет вести себя идентично исходному, если в вычислениях не будет переполнения, но он может работать вечно даже на аппаратных платформах, где целочисленное переполнение обычно имеет согласованную семантику обтекания.