Till today my understanding of the concepts function and return statement was like this:
When the control reaches the end of a function, the control is returned back to the caller (function). This happens regardless of whether the function has a
return
statement or not.
ISO C on exit()
While reading about termination of a C program, I saw a statement from ISO C (7.22.4.4.6) -
The exit function cannot return to its caller.
This statement was contradicting to my previous understanding.
ISO C on return statement
So I checked ISO C's comment (6.8.6.4) on return
statement and found this:
- A return statement with an expression shall not appear in a function whose return type is void. A return statement without an expression shall only appear in a function whose return type is void.
- A return statement terminates execution of the current function and returns control to its caller. A function may have any number of return statements.
My new conclusion
- The 'return' statement makes the host environment to compulsarily return control to the caller (function).
- In case of functions with return type of
void
, if it contains thereturn
statement, then the host environment must return back control to the caller (function). Else (i.e., ifreturn
statement is not present), then host environment may return control to the caller.- Many implementations, by default, choose to return back control to the caller function, even if the callee function doesn't have
return
statement, but except in the case ofexit()
(this exception maybe extended to some other functions as well).
Are my conclusions correct?
CodePudding user response:
Your functions are inside your program. They are not part of the host environment. The host environment is outside your program. In an ordinary general-purpose multi-user system, the host environment is the operating system (including things like a command-line shell used to execute programs).
return
statements return to calling functions inside your program. Program control flowing to the closing }
of a function returns control to the calling function. Calling exit
does not return to a function inside your program; it makes a request to the operating system to terminate the program. (However, before making this final request, exit
may perform various clean-up work and call exit handlers, so some functions within your program may still execute before the program is terminated.)
CodePudding user response:
All you quote from the standard is, of course, correct, and not contradicting.
exit()
But the description of the exit()
function has nothing to do with what a return statement does. That is mainly because it does not contain one, or at least never reaches one. It also never reaches its end. Instead, it instructs the operating system, e.g. Linux or Windows, to stop executing the program entirely, while the program still is executing the exit function. This is why exit()
never returns: It simply stops and is removed from memory instead, together with the rest of the program. Not only does it not return; there is nothing left to return to.
Calling and returning from functions
A function call is essentially a jump to a different machine code instruction, plus some niceties. For example, the address from which we are jumping is stored so that we know where to continue when the function has ended, and arguments are stored somewhere so that the called function can access them. Returning from a function is, again, a jump, to the memorized return address, plus some niceties like putting the return value, if any, in a place where the caller can access it. Reaching the end of a function is exactly equivalent to hitting a return statement, there is no functional difference.
The code that "calls" a function, and the code that returns from it, is entirely produced by the compiler. The operating system is not involved. The code is part of the binary the compiler has produced.
Using operating system facilities
Terminating a program, by contrast, is one of the basic services every operating system provides to programs. The code that does that is not part of the program but of the operating system like Linux or Windows. Programs which want to utilize such operating system services must make system calls2. One such call under Windows could be ExitProcess()
, which is perhaps what gets called at some point by the C Standard Library's exit()
implementation for Windows. Because this will cause Windows to stop the current process, code after that in exit()
is never executed, including any code that would return control to the calling function, e.g. main()
.
One of the reasons that C programs are portable between operating systems is a wrapper that shields C programs from the particularities of any given operating system1: The Standard C Library.
Without the standard library, a C program for Windows would call e.g. ReadFile()
or ExitProcess()
while a Posix program would call read()
or _exit()
. Porting a program from one operating system to another would make changes to the source code necessary. By contrast, a C program using only the standard library calls fread()
and exit()
(that page contains both the documentation for the Posix platform specific _exit()
function as well as the Standard C library function exit()
) will re-compile on any platform that has a C compiler with a standard library: The adaptation to a new operating system is necessary only once and is then available to all programs.
Your questions
Now we are able to answer your questions.
No, the
return
statement does not cause any interaction with the operating system. Everything stays within the running process, and no system resources whatsoever are used or freed.3Returning because of a
return
statement or because the end of the function is reached is exactly equivalent. The code generated is exactly equivalent. Returning the control flow to the calling function is mandatory in both cases. (The reason theexit()
function does not return is because it terminates the process before it reaches either its end or a return statement. If it did reach either one, it would return and the caller would resume execution.)This is answered in the previous paragraph; just to clarify: A conforming implementation is not free to choose between returning or not returning to the caller when the end of function is reached; it always must do so. The
exit()
function simply never reaches its end.
1 It is noteworthy that the operating system itself already provides a standardization layer: Every program using the Windows API can use ReadFile()
, independent of the particular file system and I/O chipset used on the specific machine. The C Standard Library then is an abstraction/standardization layer on top of those abstraction layers.
2 I use "system call" here a bit loosely as "function in the native OS API".
3 Unless the function is executed in a separate task, which is a different matter altogether.