Yesterday, I was asked about tail recursion and the processing of it by the compiler. I have never studied it and the explanation is vague.
The record is as follows:
Recursion includes linear recursion (Common recursion) and tail recursion.
Due to the special nature of tail recursion, the general compiler will do some special processing. Therefore, efficiency and overhead are better than normal recursion.
For example, calculate n!
1) linear recursion:
Type recurve (long N)
{
Return (n = 1 )? 1: N * recurve (n-1 );
}
2) tail recursion:
Type recurve_tail (long N, long result)
{
Return (n = 1 )? Result: recurve_tail (n-1, result * n );
}
Encapsulated in 1) format:
Type recurve (long N)
{
Return (n = 0 )? 1: recurve_tail (n, 1 );
}
Analysis:
It is easy to see that regular linear recursion consumes more resources than tail recursion. Each call leads to a longer call chain, and the system has to open up a new stack for data storage and recovery.
This problem does not exist because the State is completely saved by N and A, and the value returned by the called function is the required value. This function has no effect, therefore, this function is no longer saved and is directly called recursively on the function stack,
In special cases, you can do this directly in registers without using the memory space.
How does the compiler determine whether tail recursion works?
The returned value is the function, and there is no other choice.
Let's take a look at the compilation results of the above-mentioned tail recursive functions that were not optimized under GCC 4.3.2-1-1:
1. File"Rec. c"
2. Text
3. GloblRecurve_tail
4. TypeRecurve_tail, @ Function
5 recurve_tail:
6 pushl % EBP
7 movl % ESP, % EBP
8 subl $24, % ESP
9 CMPL $1,
8 (% EBP)
10 je. l2
11 movl
12 (% EBP), % eax
12 movl % eax, % edX
13 imull 8 (% EBP), % edX
14 movl
8 (% EBP), % eax
15 subl $1, % eax
16 movl % edX,
4 (% ESP)
17 movl % eax, (% ESP)
18 call
Recurve_tail
19 movl % eax,-4 (% EBP)
20 JMP. l3
21. L2:
22 movl
12 (% EBP), % eax
23 movl % eax,-4 (% EBP)
24. L3:
25 movl-4 (% EBP), % eax
26 leave
27 RET
28. SizeRecurve_tail,.-recurve_tail
29. Ident"GCC: (Debian 4.3.2-1.1)
4.3.2"
30. Section
. Note. GNU-Stack, "", @ progbits
No optimization is performed, which is the same as the normal recursive processing method. The stack is newly opened. Then, we can look at the-O3 optimization result:
1. File"Rec. c"
2. Text
3. p2align 4, 15
4. GloblRecurve_tail
5. TypeRecurve_tail, @ Function
6 recurve_tail:
7 pushl % EBP
8 movl % ESP, % EBP
9 movl
8 (% EBP), % edX
10 movl
12 (% EBP), % eax
11 CMPL $1, % edX
12 JE. l2
13. p2align 4, 7
14. p2align 3
15. l5:
16 imull % edX, % eax
17 subl $1, % edX
18 CMPL $1, % edX
19 JNE. l5
20. L2:
21 popl % EBP
22 RET
23. SizeRecurve_tail,.-recurve_tail
24. Ident"GCC: (Debian 4.3.2-1.1)
4.3.2"
25. Section
. Note. GNU-Stack, "", @ progbits
At this point, as analyzed above, this space computing has not opened up a new stack.