Như những người khác đã lưu ý, chỉ có thể nếu (1) trình biên dịch của bạn hỗ trợ tối ưu hóa cuộc gọi đuôi và (2) nếu chức năng của bạn đủ điều kiện để tối ưu hóa như vậy. Tối ưu hóa là sử dụng lại ngăn xếp hiện có và thực hiện một JMP (tức là, một GOTO trong lắp ráp) thay vì một CALL.
Thực tế, chức năng mẫu của bạn thực sự đủ điều kiện để tối ưu hóa như vậy. Lý do là điều cuối cùng mà chức năng của bạn làm trước khi trở về là tự gọi; nó không phải làm bất cứ điều gì sau cuộc gọi cuối cùng đến funcnew()
. Tuy nhiên, chỉ một số trình biên dịch sẽ thực hiện tối ưu hóa như vậy. GCC, ví dụ, sẽ làm điều đó. Để biết thêm thông tin, hãy xem Which, if any, C++ compilers do tail-recursion optimization?
Tài liệu cổ điển về điều này là chức năng giai thừa. Hãy tạo một hàm giai thừa đệ quy là không đủ điều kiện để tối ưu hóa cuộc gọi đuôi (TCO).
int fact(int n)
{
if (n == 1) return 1;
return n*fact(n-1);
}
Điều cuối cùng cần làm là nhân sốvới kết quả từ fact(n-1)
. Bằng cách nào đó loại bỏ hoạt động cuối cùng này, chúng tôi sẽ có thể tái sử dụng ngăn xếp. Hãy giới thiệu một biến ắc mà sẽ tính toán câu trả lời cho chúng ta:
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);
}
Chức năng fact_helper
làm việc, trong khi fact_acc
chỉ là một chức năng thuận tiện để khởi tạo biến accumulator.
Lưu ý cách điều mới nhất fact_helper
thực hiện là tự gọi. CALL này có thể được chuyển đổi thành JMP bằng cách tái sử dụng ngăn xếp hiện có cho các biến.
Với GCC, bạn có thể xác minh rằng nó được tối ưu hóa để một bước nhảy bằng cách nhìn vào lắp ráp tạo ra, ví dụ :
...
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
...
Một số ngôn ngữ lập trình, chẳng hạn như Scheme, trên thực tế sẽ đảm bảo rằng việc triển khai thích hợp sẽ thực hiện tối ưu hóa như vậy. Họ thậm chí sẽ làm điều đó cho các cuộc gọi đuôi không đệ quy.
Tôi không thấy "tự gọi hàm" trong mẫu mã của bạn. – AnT
'tĩnh' là bạn của bạn? (vẫn không có điều kiện kết thúc, bạn sẽ ngăn xếp tràn với con trỏ trả lại). –