Problem with Tail Recursion in g++
I'm was messing around with tail-recursive functions in C++, and I've run into a bit of a snag with the g++ compiler.
The following code results in a stack overflow when numbers[]
is over a couple hundred integers in size. Examining the assembly code generated by g++ for the following reveals that twoSum_Helper is executing a recursive call
instruction to itself.
The question is which of the following is causing this?
I am compiling with g++ -O3 -Wall -fno-stack-protector test.c
on Windows Vista x64 via MinGW with g++ 4.5.0.
struct result
{
int i;
int j;
bool found;
};
struct result gen_Result(int i, int j, bool found)
{
struct result r;
r.i = i;
r.j = j;
r.found = found;
return r;
}
// Return 2 indexes from numbers that sum up to target.
struct result twoSum_Helper(int numbers[], int size, int target, int i, int j)
{
if (numbers[i] + numbers[j] == target)
return gen_Result(i, j, true);
if (i >= (size - 1))
return gen_Result(i, j, false);
if (j >= size)
return twoSum_Helper(numbers, size, target, i + 1, i + 2);
else
return twoSum_Helper(numbers, size, target, i, j + 1);
}
Tail call optimization in C or C++ is extremely limited, and pretty much a lost cause. The reason is that there generally is no safe way to tail-call from a function that passes a pointer or reference to any local variable (as an argument to the call in question, or in fact any other call in the same function) -- which of course is happening all over the place in C/C++ land, and is almost impossible to live without.
The problem you are seeing is probably related: GCC likely compiles returning a struct by actually passing the address of a hidden variable allocated on the caller's stack into which the callee copies it -- which makes it fall into the above scenario.
Try compilling with -O2 instead of -O3.
How do I check if gcc is performing tail-recursion optimization?
well, it doesn't work with O2 anyway. The only thing that seems to work is returning the result
object into a reference that is given as a parameter.
but really, it's much easier to just remove the Tail call and use a loop instead. TCO is here to optimize tail call that are found when inlining or when performing agressive unrolling, but you shouldn't attempt to use recursion when handling large values anyway.
I can't get g++ 4.4.0 (under mingw) to perform tail recursion, even on this simple function:
static void f (int x)
{
if (x == 0) return ;
printf ("%pn", &x) ; // or cout in C++, if you prefer
f (x - 1) ;
}
I've tried -O3
, -O2
, -fno-stack-protector
, C and C++ variants. No tail recursion.
上一篇: 在scala中递归优化?
下一篇: g ++中的尾递归问题