Is there any difference between return n
(in the main
function) and exit(n)
in C? Is it defined by C or POSIX standards or it depends on OS or compiler?
4 Answers
In most cases, there's no difference, but here's a C program that's likely to behave differently depending on whether it uses return 0;
or exit(0);
:
#include <stdio.h>
#include <stdlib.h>
static char *message;
void cleanup(void) {
printf("message = \"%s\"\n", message);
}
int main(void) {
char local_message[] = "hello, world";
message = local_message;
atexit(cleanup);
#ifdef USE_EXIT
puts("exit(0);");
exit(0);
#else
puts("return 0;");
return 0;
#endif
}
Because of the atexit()
call, either exit(0);
or return 0;
causes the cleanup
function to be invoked. The difference is that if the program calls exit(0);
, the cleanup happens while the "call" to main()
is still active, so the local_message
object still exists. Executing return 0;
, however, immediately terminates the invocation of main()
and then invokes the cleanup()
function. Since cleanup()
refers (via the global message
pointer) to an object that's allocated locally to main
, and that object no longer exists, the behavior is undefined.
Here's the behavior I see on my system:
$ gcc -DUSE_EXIT c.c -o c && ./c
exit(0);
message = "hello, world"
$ gcc c.c -o c && ./c
return 0;
message = ""
$
Running the program without -DUSE_EXIT
could do anything, including crashing or printing "hello, world"
(if the memory used by local_message
happens not to be clobbered).
In practice, though, this difference only shows up if objects defined locally inside main()
are made visible outside main()
by saving pointers to them. This could plausibly happen for argv
. (Experiment on my system shows that the objects pointed to by argv
and by *argv
continue to exist after returning from main()
, but you shouldn't depend on that.)
For C
The Standard says that a return from the initial call to main is equivalent to calling exit. However, a return from main cannot be expected to work if data local to main might be needed during cleanup.For C++
When exit(0) is used to exit from program, destructors for locally scoped non-static objects are not called. But destructors are called if return 0 is used.
Program 1 – - uses exit(0) to exit
#include<iostream>
#include<stdio.h>
#include<stdlib.h>
using namespace std;
class Test {
public:
Test() {
printf("Inside Test's Constructor\n");
}
~Test(){
printf("Inside Test's Destructor");
getchar();
}
};
int main() {
Test t1;
// using exit(0) to exit from main
exit(0);
}
Output: Inside Test’s Constructor
Program 2 – uses return 0 to exit
#include<iostream>
#include<stdio.h>
#include<stdlib.h>
using namespace std;
class Test {
public:
Test() {
printf("Inside Test's Constructor\n");
}
~Test(){
printf("Inside Test's Destructor");
}
};
int main() {
Test t1;
// using return 0 to exit from main
return 0;
}
Output:
Inside Test’s Constructor
Inside Test’s Destructor
Calling destructors is sometimes important, for example, if destructor has code to release resources like closing files.
Note that static objects will be cleaned up even if we call exit(). For example, see following program.
#include<iostream>
#include<stdio.h>
#include<stdlib.h>
using namespace std;
class Test {
public:
Test() {
printf("Inside Test's Constructor\n");
}
~Test(){
printf("Inside Test's Destructor");
getchar();
}
};
int main() {
static Test t1; // Note that t1 is static
exit(0);
}
Output:
Inside Test’s Constructor
Inside Test’s Destructor
-
Closing files isn't really a good example of an important destructor to fire when you are exiting, because files will be closed on program exit anyways. Oct 28, 2012 at 13:29
-
1@WinstonEwert: True, but there might exist application-level buffers that still need to be flushed.– PhilippOct 28, 2012 at 13:46
-
1
-
I know neither language so forgive me, but this answer makes me think exit is like C#'s failfast, so in C++ does exit in a try execute a finally? Oct 28, 2012 at 20:54
-
Its worth noting that C standard (C99) defines two types of execution environments, Freestanding Environment and Hosted Environment. Freestanding environment is a C environment which does not support the C libraries and is intended for embedded applications and the like. A C environment which supports the C libraries is called a Hosted environment.
C99 says, in a Freestanding environment program termination is implementation defined. So, if the implementation defines main
, return n
, and exit
, their behaviors are as is defined in that implementation.
C99 defines Hosted environment behavior as,
If the return type of the main function is a type compatible with it, a return from the initial call to the main function is equivalent to calling the exit function with the value returned by the main function as its argument; reaching the } that terminates the main function returns a value of 0. If the return type is not compatible with int, the termination status returned to the host environment is unspecified.
-
1And it really doesn't make any sense to call exit() from a freestanding environment. The embedded equivalent of exit() would be to hang the program in an eternal loop, then wait for the watchdog to time out.– user29079Oct 29, 2012 at 7:24
From the C standard's perspective, not really, other than return
being a statement and exit()
being a function. Either will cause any functions registered with atexit()
to be called followed by termination of the program.
There are a couple of situations you want to watch out for:
- Recursion in
main()
. While rarely seen in practice, it is legal in C. (C++ explicitly forbids it.) - Re-use of
main()
. Sometimes an existingmain()
will be renamed something else and be called by a newmain()
.
The use of exit()
will introduce a bug if either of those happens after you've written the code, especially if not terminating abnormally. To avoid that, it's a good idea to be in the habit of treating main()
as the function it is and using return
when you want it to end.