1

i'm learning about functions and decided to make a loop where two function(in this case funcA and funcB ) call each other forever but it stops execution after some time. The code looks like this:

#include <iostream>

void funcA(); //forward declaration

//funcB calls funcA 
void funcB()
{
    funcA();
}

//funcA prints 1 and calls funcB again 
void funcA()
{
    std::cout<<1;
    funcB();
}

//main calls funcB
int main()
{
    funcB();
    return 0;
}  

the returned value is -1073741571 (0xC00000FD). can you expain why this happens?

templatetypedef
  • 362,284
  • 104
  • 897
  • 1,065
SgerS1
  • 131
  • 5
  • 1
    You program will cause a stack overflow and exit. – Paul Baxter Jul 31 '19 at 16:08
  • This depends of compilation flags and compiler. Compiler can transform this code into infinitive loop (tail recursion) and stack will not overflow. We need more information to explain that return code. How do you build this code: compiler, its flags and what OS. How do you run it. – Marek R Jul 31 '19 at 16:15
  • @Cromon Don't write answers in comments please. I see you've also posted it as an answer so the comment can just be deleted. – Lightness Races in Orbit Jul 31 '19 at 16:17
  • 3
    Possible duplicate of [Clion exit code -1073741571 (0xC00000FD)](https://stackoverflow.com/questions/53009030/clion-exit-code-1073741571-0xc00000fd) – Marek R Jul 31 '19 at 16:17
  • @MarekR Compiler:GNU GCC Flags:C++11 ISO standard [-std=c++11] OS:Windows 10 – SgerS1 Jul 31 '19 at 16:28

3 Answers3

4

While in theory this goes on forever the problem is that every time a function is called some memory needs to be reserved on something called the 'stack'. Eventually there is no more space left on that 'stack' and you get a StackOverflowException. 0xC00000FD is the error code windows uses to tell you that a StackOverflowException happened

Guillaume Racicot
  • 39,621
  • 9
  • 77
  • 141
Cromon
  • 821
  • 10
  • 24
4

Whenever you call a function, the program reserved a small amount of space to hold information for that function (space for local variables, information about where to return to after the function exits, etc.). This memory is allocated from a region called the call stack (or “stack” for short), and it’s returned to the stack when the function finishes running.

The stack typically has a fixed, small size. If you have a very long chain of calls (usually measured in tens of thousands of calls), you can run out of stack space and the program will terminate with an error called a stack overflow. That’s what’s happening in your program.

Generally speaking, if you have recursive (or in your case, mutually recursive) functions, you’ll need to make sure that the recursion depth doesn’t get “too large” for some definition of “too large,” or this sort of thing can happen. There are some special cases where some compilers can recognize that you’re writing recursive code and transform it into code that doesn’t allocate multiple stack frames (see “tail-call elimination” for more details), but that’s the exception rather than the rule.

templatetypedef
  • 362,284
  • 104
  • 897
  • 1,065
4

Ok so since this is gcc on Windows 10 take a look on this goodbolt

Without any optimization enabled both functions are explicitly called.

b():
        push    rbp
        mov     rbp, rsp
        call    foo()
        call    a()
        nop
        pop     rbp
        ret
a():
        push    rbp
        mov     rbp, rsp
        call    b()
        nop
        pop     rbp
        ret

As other answer point out each call leaves on stack information how to come back to function which called function. Now since functions never return this information is never removed from stack, but is constantly added. As a result you have got stack overflow which on Windows is indicated by value 0xC00000FD.

Now if you enable optimization (-O2) compiler is able to figure out this is infinitive loop (using technique called tail recursion).

b():
        sub     rsp, 8
.L2:
        call    foo()
        jmp     .L2
a():
        sub     rsp, 8
.L6:
        call    foo()
        jmp     .L6

So with optimization enabled you will have infinitive loop as you are expecting.

Marek R
  • 32,568
  • 6
  • 55
  • 140
  • since i don't have a good knowledge in c++(yet) and this "stack" , "tail recursion", "recursion" concepts are new for me i still have some questions. despite this, all of the answers helped me to understand those concepts. so if i get it right when function is called, computer must remember the address where it came from and that information is stored in allocated memory called "call stack" which is around 1MB and because function is recursive it adds more and more repetitive addresses. That's where tail recursion comes in game right? – SgerS1 Jul 31 '19 at 19:06
  • in your code, those keywords "sub" "jmp" "rsp" "call".. i guess are actions which tail recursion technique takes but i don't understand their meanings. i turned on -O2 optimization but it didn't worked(Code::Blocks). is there any other manual way to optimize the code? – SgerS1 Jul 31 '19 at 19:11
  • To understand outcome of godbolt you have to be familiar with assembly code (CPU instructions). `call` instruction is a jump which add come back address on stack. Later `ret` instruction takes this address from stack and jumps to that address. – Marek R Jul 31 '19 at 22:53
  • Where is `foo()`? – curiousguy Aug 05 '19 at 09:14
  • @curiousguy nowhere. It is not needed to show how compiler resolves code. So it is just declared as external. Adding `foo` with code would make compiler optimize more stuff what could hide actual topic. – Marek R Aug 05 '19 at 17:49