Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

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?

share|improve this question

4 Answers 4

up vote 4 down vote accepted

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.)

share|improve this answer

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 existing main() will be renamed something else and be called by a new main().

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.

share|improve this answer

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.

share|improve this answer
1  
And 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. –  user29079 Oct 29 '12 at 7:24
  • 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

share|improve this answer
    
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. –  Winston Ewert Oct 28 '12 at 13:29
1  
@WinstonEwert: True, but there might exist application-level buffers that still need to be flushed. –  Philipp Oct 28 '12 at 13:46
1  
The question does not mention C++ anywhere... –  tdammers Oct 28 '12 at 15:48
    
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? –  Jimmy Hoffa Oct 28 '12 at 20:54
    
@JimmyHoffa, c++ doesn't have finally –  Winston Ewert Oct 28 '12 at 22:16

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.