O tipo de condicional usado em um loop pode limitar os tipos de otimizações que um compilador pode executar, para melhor ou para pior. Por exemplo, dado:
uint16_t n = ...;
for (uint16_t i=1; i<=n; i++)
... [loop doesn't modify i]
um compilador pode assumir que a condição acima deve fazer com que o loop saia após o enésimo enésimo passo, a menos que n possa 65535 e o loop possa sair de alguma outra maneira que não seja i excedendo n. Se essas condições se aplicarem, o compilador deverá gerar um código que faça com que o loop seja executado até que algo diferente da condição acima faça com que ele saia.
Se o loop tivesse sido escrito como:
uint16_t n = ...;
for (uint16_t ctr=0; ctr<n; ctr++)
{
uint16_t i = ctr+1;
... [loop doesn't modify ctr]
}
então, um compilador poderia assumir com segurança que o loop nunca precisaria ser executado mais de n vezes e, portanto, seria capaz de gerar código mais eficiente.
Observe que qualquer estouro com tipos assinados pode ter consequências desagradáveis. Dado:
int total=0;
int start,lim,mult; // Initialize values somehow...
for (int i=start; i<=lim; i++)
total+=i*mult;
Um compilador pode reescrever isso como:
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;
Esse loop se comportaria de forma idêntica ao original se não ocorrer um estouro nos cálculos, mas poderá ser executado para sempre, mesmo em plataformas de hardware onde o excesso de números normalmente teria semântica de empacotamento consistente.