The type of conditional used in a loop may limit the kinds of optimizations a compiler can perform, for better or for worse. For example, given:
uint16_t n = ...;
for (uint16_t i=1; i<=n; i++)
... [loop doesn't modify i]
a compiler could assume that the above condition should cause the loop to
exit after the nth pass loop unless n might 65535 and the loop might exit
in some fashion other than by i exceeding n. If those conditions apply,
the compiler must generate code which would cause the loop to run until something other than the above condition causes it to exit.
If the loop had instead been written as:
uint16_t n = ...;
for (uint16_t ctr=0; ctr<n; ctr++)
{
uint16_t i = ctr+1;
... [loop doesn't modify ctr]
}
then a compiler could safely assume that the loop would never need to
execute more than n times and may thus be able to generate more efficient
code.
Note that any overflow with signed types can have nasty consequences.
Given:
int total=0;
int start,lim,mult; // Initialize values somehow...
for (int i=start; i<=lim; i++)
total+=i*mult;
A compiler might rewrite that as:
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;
Such a loop would behave identically to the original if no overflow
occur in the calculations, but could run forever even on hardware
platforms where integer overflow would normally have consistent wrapping
semantics.