- return is a statement of the language returned from a function call.
- exit is a system call (not a language statement) that terminates the current process.
The only case where both do (almost) the same thing in the main() function, since returning from main does exit() .
Example with return :
#include <stdio.h> void f(){ printf("Executing f\n"); return; } int main(){ f(); printf("Back from f\n"); }
If you run this program, it will print:
Executing f Back from f
Another example for exit() :
#include <stdio.h> #include <stdlib.h> void f(){ printf("Executing f\n"); exit(0); } int main(){ f(); printf("Back from f\n"); }
If you run this program, it will print:
Executing f
You will never get "Back with f". Also note the #include <stdlib.h> needed to call the library function exit() .
Also note that the exit() parameter is an integer (this is the return status of the process that the start process can receive, normal use is 0 for success, or any other value for the error).
The return statement parameter is any type of function return value. If the function returns void, you can omit the return at the end of the function.
The last point, exit() is presented in two variants _exit() and exit() . The difference between the forms is that exit() (and returning from the main one) calls the functions registered using atexit() or on_exit() before actually terminating the process, and _exit() (from #include <unistd.h> or its synonym _Exit from #include <stdlib.h> ) immediately terminates the process.
Now there are also problems specific to C ++.
C ++ does a lot more work than C when it exits functions ( return -ing). In particular, it calls the destructors of local objects that go out of scope. In most cases, programmers will not care about the state of the program after the process is stopped, so it does not really matter: the allocated memory will be freed, the file will be closed, etc. But it can make a difference if your destructor does IO. For example, the automatic creation of C ++ OStream will not be cleared locally when called to exit, and you may lose some uncommitted data (on the other hand, the static OStream will be reset).
This will not happen if you use the good old C FILE* streams. They will be reset to exit() . In fact, the rule is the same as for registered exit functions, FILE* will be reset at all normal endings, including exit() , but will not call _exit() or abort ().
You should also keep in mind that C ++ provides a third way to exit a function: throwing an exception. This way to exit the function will call the destructor. If it does not fall into the caller chain, the exception may go to the main () function and terminate the process.
C ++ static object destructors (globals) will be called if you call either return from main() or exit() anywhere in your program. They will not be called if the program terminates using _exit() or abort() . abort() is mainly useful in debugging mode to immediately stop the program and get a stack trace (for post mortem analysis). Usually it is hidden behind the assert() macro, which is only active in debug mode.
When is exit () function useful?
exit() means you want to immediately stop the current process. This can be useful for error management when we encounter some kind of an irrevocable problem that will no longer allow your code to do anything useful. This is often convenient when the control flow is complex and error codes should be distributed everywhere. But keep in mind that this is the wrong coding practice. Quiet process termination in most cases should be preferable to worse behavior and actual error management (or in C ++ using exceptions).
Direct calls to exit() especially bad if they are executed in libraries, because they will doom the library user, and this should be the choice of the library user to implement some kind of error correction or not. If you need an example of why calling exit() from a library is bad, this leads, for example, to people who ask this question .
There is an undeniable legitimate use of exit() as a way to terminate the child process launched by fork () on the operating systems that support it. Going back to the code before fork () is usually a bad idea. This is an explanation of why the functions of the exec () family never return to the caller.