Я хотел проверить, поддерживает ли g++ хвост, поэтому я написал эту простую программу, чтобы проверить его: http://ideone.com/hnXHv
using namespace std;
size_t st;
void PrintStackTop(const std::string &type)
{
int stack_top;
if(st == 0) st = (size_t) &stack_top;
cout << "In " << type << " call version, the stack top is: " << (st - (size_t) &stack_top) << endl;
}
int TailCallFactorial(int n, int a = 1)
{
PrintStackTop("tail");
if(n < 2)
return a;
return TailCallFactorial(n - 1, n * a);
}
int NormalCallFactorial(int n)
{
PrintStackTop("normal");
if(n < 2)
return 1;
return NormalCallFactorial(n - 1) * n;
}
int main(int argc, char *argv[])
{
st = 0;
cout << TailCallFactorial(5) << endl;
st = 0;
cout << NormalCallFactorial(5) << endl;
return 0;
}
Когда я скомпилировал его, как обычно, g++ не замечает никакой разницы между двумя версиями:
> g++ main.cpp -o TailCall
> ./TailCall
In tail call version, the stack top is: 0
In tail call version, the stack top is: 48
In tail call version, the stack top is: 96
In tail call version, the stack top is: 144
In tail call version, the stack top is: 192
120
In normal call version, the stack top is: 0
In normal call version, the stack top is: 48
In normal call version, the stack top is: 96
In normal call version, the stack top is: 144
In normal call version, the stack top is: 192
120
Разница в стеках составляет 48 в обоих из них, тогда как для версии хвостового вызова требуется еще одна
внутр. (Почему?)
Поэтому я думал, что оптимизация может быть удобной:
> g++ -O2 main.cpp -o TailCall
> ./TailCall
In tail call version, the stack top is: 0
In tail call version, the stack top is: 80
In tail call version, the stack top is: 160
In tail call version, the stack top is: 240
In tail call version, the stack top is: 320
120
In normal call version, the stack top is: 0
In normal call version, the stack top is: 64
In normal call version, the stack top is: 128
In normal call version, the stack top is: 192
In normal call version, the stack top is: 256
120
Размер стека увеличился в обоих случаях, и, хотя компилятор может думать, что мой процессор медленнее, чем моя память (что его не так), я не знаю, почему 80 байтов необходимы для простой функции. (Почему?).
Такая версия хвостового вызова занимает больше места, чем обычная версия, и вполне логична, если int имеет размер 16 байт. (нет, у меня нет 128-битного процессора).
Теперь, подумав, почему компилятор не позвонил в хвост, я думал, что это могут быть исключения, потому что они сильно зависят от стека. Поэтому я пробовал без исключений:
> g++ -O2 -fno-exceptions main.cpp -o TailCall
> ./TailCall
In tail call version, the stack top is: 0
In tail call version, the stack top is: 64
In tail call version, the stack top is: 128
In tail call version, the stack top is: 192
In tail call version, the stack top is: 256
120
In normal call version, the stack top is: 0
In normal call version, the stack top is: 48
In normal call version, the stack top is: 96
In normal call version, the stack top is: 144
In normal call version, the stack top is: 192
120
Что вырезать нормальную версию обратно в неоптимизированный размер стека, а оптимизированный - по 8 байтов. еще int не 8 байтов.
Я думал, что есть что-то, что я пропустил в С++, которому нужен пакет, поэтому я попробовал c: http://ideone.com/tJPpc
Тем не менее хвост не звонит, но стек намного меньше (32 бит каждого кадра в обеих версиях).
Затем я попытался с оптимизацией:
> gcc -O2 main.c -o TailCall
> ./TailCall
In tail call version, the stack top is: 0
In tail call version, the stack top is: 0
In tail call version, the stack top is: 0
In tail call version, the stack top is: 0
In tail call version, the stack top is: 0
120
In normal call version, the stack top is: 0
In normal call version, the stack top is: 0
In normal call version, the stack top is: 0
In normal call version, the stack top is: 0
In normal call version, the stack top is: 0
120
Не только его хвостовой вызов оптимизировал первый, но и хвостовой вызов оптимизировал второй!
Почему g++ не оптимизирует оптимизацию звонка, пока он явно доступен на платформе? есть ли способ заставить его?