11

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?

0

4 Answers 4

11

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

18
  • 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

5
  • 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.
    – Philipp
    Oct 28, 2012 at 13:46
  • 1
    The question does not mention C++ anywhere...
    – tdammers
    Oct 28, 2012 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? Oct 28, 2012 at 20:54
  • @JimmyHoffa, c++ doesn't have finally Oct 28, 2012 at 22:16
6

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.

1
  • 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, 2012 at 7:24
0

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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.