Como han señalado otros, solo es posible si (1) su compilador admite la optimización de la cola de llamadas, y (2) si su función es elegible para dicha optimización. La optimización es reutilizar la pila existente y realizar un JMP (es decir, un GOTO en el ensamblaje) en lugar de una LLAMADA.
De hecho, su función de ejemplo es elegible para dicha optimización. La razón es que lo último que hace su función antes de regresar es llamarse a sí mismo; no tiene que hacer nada después de la última llamada al funcnew()
. Sin embargo, solo ciertos compiladores realizarán dicha optimización. GCC, por ejemplo, lo hará. Para obtener más información, consulte Which, if any, C++ compilers do tail-recursion optimization?
El material clásico sobre esto es la función factorial. Vamos a hacer una función factorial recursiva que es no elegible para la optimización de la cola de llamadas (TCO).
int fact(int n)
{
if (n == 1) return 1;
return n*fact(n-1);
}
La última cosa que hace es multiplicar n
con el resultado de fact(n-1)
. Al eliminar de alguna manera esta última operación, podríamos reutilizar la pila. Vamos a introducir una variable acumulador que calcular la respuesta para nosotros:
int fact_helper(int n, int acc)
{
if (n == 1) return acc;
return fact_helper(n-1, n*acc);
}
int fact_acc(int n)
{
return fact_helper(n, 1);
}
La función fact_helper
hace el trabajo, mientras que fact_acc
es sólo una función de conveniencia para inicializar la variable acumulador.
Observe cómo el último cosa fact_helper
hace es llamar a sí mismo. Esta llamada se puede convertir a un JMP reutilizando la pila existente para las variables.
con gcc, se puede comprobar que está optimizado para un salto mirando el ensamblado generado, por ejemplo :
...
37 L12:
38 0040 0FAFC2 imull %edx, %eax
39 0043 83EA01 subl $1, %edx
40 0046 83FA01 cmpl $1, %edx
41 0049 75F5 jne L12
...
Algunos lenguajes de programación, tales como Scheme, en realidad garantizar que las implementaciones adecuadas se realizar tales optimizaciones. Incluso lo harán por llamadas de cola no recursivas.
No veo "función llamar a sí mismo" en el ejemplo de código. – AnT
'static' es tu amigo? (sin condiciones de finalización, se acumulará desbordamiento con punteros de retorno). –