The sort of software these rules are intended for run in constrained environments. The other question besides "Will this loop/recursion terminate?" is "Will we blow up the stack?".
Ignoring the time required to establish a new stackframe (versus a mere jump for a loop), the creation of a stack frame uses more memory. The less memory you can use, while still producing maintainable code, the better. And an easy way to assist with this is to remove recursion.
You could make the case for tail recursion, which a sufficiently advanced compiler will/can/should turn into a mere jump, like a loop, because it is. But this isn't guaranteed in the C standard and so should not be relied upon.
And then there's Rule #2. Loops are bounded, the index variable is supposed to only be altered by the loop structure (so: `for(i = 0; i < MAX; i++)`, that increment is the only place `i` should be altered). By providing a compile-time max, and incrementing (deterministically) the index variable, you ensure that static analysis of the loop terminating (or not) is possible.
Tali recursion should be equivalent to a loop, if the language compiler/implementation offers TCE/TCO. C does not guarantee this.
But I'll also point out, tail recursion could be statically analyzed in the same way that you would with a for loop (for the purpose of Rule 2). As long as it is structured in a way that demonstrates that:
1) Forward progress is always being made (that is, there's an iteration/index parameter that always increases/decreases monotonically) towards a bound:
void f(state,n)
{
if(n > MAX) return;
f(g(state),n+1);
}
2) There's a single entry point which initiates the recursion (loop) with 0 (or MAX if you're decrementing, or whatever):
void start(state)
{
f(state,0);
}
Both can be demonstrated (with code structured like the above) statically.
A modified C compiler could be built that would do TCO. But, for this kind of application, it would mean that you'd have to re-validate your compiler, so that's pretty much not going to happen.
Looking it up, it seems that GCC (at least) presently does do (at some optimization levels) tail call elimination. Others probably do as well. I guess I've never looked it up because it was never relevant (if I'm using C, I might as well use for loops, they're at least as clear as the equivalent tail recursive function).
Ignoring the time required to establish a new stackframe (versus a mere jump for a loop), the creation of a stack frame uses more memory. The less memory you can use, while still producing maintainable code, the better. And an easy way to assist with this is to remove recursion.
You could make the case for tail recursion, which a sufficiently advanced compiler will/can/should turn into a mere jump, like a loop, because it is. But this isn't guaranteed in the C standard and so should not be relied upon.
And then there's Rule #2. Loops are bounded, the index variable is supposed to only be altered by the loop structure (so: `for(i = 0; i < MAX; i++)`, that increment is the only place `i` should be altered). By providing a compile-time max, and incrementing (deterministically) the index variable, you ensure that static analysis of the loop terminating (or not) is possible.