37

Starting with the C99 standard, the compiler is required to generate the equivalent of a return 0 or return EXIT_SUCCESS if no return is supplied at the end of main. There was also a corresponding and identical change to the C++ language standard around that same time. I am interested in the reasons for both and I guessed that it was unlikely they were entirely separate and unrelated changes.

My question is:

What was the documented rationale for this change?

An ideal answer would cite authoritative sources for both C and C++ which is why I have tagged the question with both languages.

Note that unlike the question What the reasons for/against returning 0 from main in ISO C++?, I'm not asking for advice on whether to write return 0 in my programs -- I'm asking why the language standards themselves were changed.


To help understand the purpose for the question, here is a bit more of the context:

  1. Understanding why a change was made is helpful in deciding how to use it.
  2. Rationale is frequently included within the standard itself. For example, the C90 standard includes many explanatory footnotes such as footnote 36 which starts, "The intent of this list..."

I've studied the standards searching for the answer myself before I asked here, but did not find the answer. I've been asked to help write coding standards for both languages for a group of programmers and I wanted to make sure I understand why this feature exists so that I may accurately explain its use to others.

Community
  • 1
  • 1
Edward
  • 6,964
  • 2
  • 29
  • 55
  • 2
    That question is just speculative, as it askes for the motivations of the commitee members. You should ask there to get an authoritative answer. – too honest for this site Jul 13 '15 at 22:06
  • 21
    @Olaf: Language change proposals are usually documented with the reasons for the proposed change. I'm asking for that documentation, *not* for speculation. – Edward Jul 13 '15 at 22:07
  • 2
    I'm going to guess backward compatibility. – R Sahu Jul 13 '15 at 22:09
  • 3
    C++98 preceded C99 so the answer is likely to be in WG21, not WG14 ... possibly even in pre-standard C++, does anyone have the old book? – o11c Jul 13 '15 at 22:23
  • 2
    You must return something from a non-void function. Now the default value could either indicate success or failure; but, in case of the latter, the program wouldn't have reached the end of `main`. I don't have the authoritative answer, but it sounds pretty logical. – edmz Jul 13 '15 at 22:40
  • 4
    This needs to be two questions, one for C, one for C++. Feel free to include links in each question to the other one. – Ben Voigt Jul 13 '15 at 22:42
  • 2
    The change was made between C90 and C99. As Ben's answer says, the C99 Rationale doesn't address the issue, and there do not appear to be any relevant [C90 Defect Reports](http://www.open-std.org/jtc1/sc22/wg14/www/docs/dr.htm). – Keith Thompson Jul 13 '15 at 22:54
  • 3
    The Foreword to the C99 standard includes a list of "major changes" from the previous edition. The change that made falling off the end of `main` equivalent to `return 0;` is not mentioned, and the section where the change was made (5.1.2.2.3) offers no rationale. – Keith Thompson Jul 13 '15 at 23:03
  • 3
    @RSahu: Backward compatibility with what? In C90, falling off the end of `main` returns an undefined termination status to the environment; in C99 it was made equivalent to `return 0;`. I suppose it might have been for backward compatibility with pre-ANSI (K&R) C, but adding such a compatibility feature in C99 seems odd. My guess is that it was intended to remove a gratuitous incompatibility with C++. – Keith Thompson Jul 13 '15 at 23:08
  • 2
    @jxh: I'm interested in the answers for both C++ and for C, as stated in the question. It seemed to be of little value to split it into two separate but linked questions but I could if that's really the consensus view. My guess is that one or the other committee decided first and the second decided to harmonize with the first, but that's part of the information I'm seeking. – Edward Jul 14 '15 at 01:23
  • 1
    @KeithThompson, that was a wild guess on my part. I have nothing to back up that guess. – R Sahu Jul 14 '15 at 03:27
  • 1
    C++98 went first; I tend to assume, without having followed the documentation (if the documentation is available that far back) whether there was any reason other than compatibility with C++98 for the change in C99. The pressures may have been the same as for C++98 to make the change. – Jonathan Leffler Jul 14 '15 at 03:43
  • 4
    @Olaf this is not speculative nor opinion based. Changes to C and C++ are made as part of standards process and changes all have a rationale. It may be difficult to find a public document for a particular case but a rationale does exist and it is a valid question. – Shafik Yaghmour Jul 14 '15 at 04:01
  • If there was a change in C++, it was between the pre-standard language and the very first official ISO C++ standard. – Keith Thompson Jul 14 '15 at 05:29
  • 1
    @ShafikYaghmour: Read the comments and the tell me it is not speculative on our side. I did not say the commitee members themselves did speculate (as such a statement would make no sense). Therefore, I stated to ask/check the commitee documents. – too honest for this site Jul 14 '15 at 12:06
  • 2
    @Olaf Both answers to this question cite authoritative sources, one written by the committee and one written by a long time member of the committee and compiler writer. So neither answer is speculative. Sure there could be speculative answers and they should be downvoted just like they should on any other question. If there were no public sources available the many committee members who participate on SO could always choose to answer whether they do or not does not reflect whether the question is speculative or not. – Shafik Yaghmour Jul 14 '15 at 12:48
  • 2
    Language lawyer type questions have always been considered valid C and C++ question on SO and so closing this as looking for an outside resource makes no sense. – Shafik Yaghmour Jul 14 '15 at 12:51
  • @ShafikYaghmour: Point taken about the answers although they do not cover the question completely, as that asks for C++, too. But the question is not a "language-lawyer" style question imho. It does not focus on the interpreation of a standard, but asks for the reason for a particular specification. Never mind, I think we both have better things to do than discuss further :-) – too honest for this site Jul 14 '15 at 12:58
  • 2
    Another data point: The 2nd edition of Stroustrup's "The C++ Programming Language", published in 1991, doesn't have this rule. But some of the sample programs fall off the end of `main` (apparently not caring about the return status) -- and at least one example uses implicit `int`. – Keith Thompson Jul 14 '15 at 15:09
  • The 3rd edition (1997) does include that rule explicitly, and the Annotated Reference Manual (ARM), 1990 does not. The ARM does, however, include at least one example in which there is no explicit `return` from main. – Edward Jul 14 '15 at 15:24
  • 2
    Compare the C++ working paper from [Sep. '93](http://www.open-std.org/jtc1/sc22/wg21/docs/wp/pdf/sep93/) and the one from [Jan. '94](http://www.open-std.org/jtc1/sc22/wg21/docs/wp/pdf/jan94/). The latter one contains: “If control reaches the end of `main` without encountering a `return` statement, the effect is that of executing `return 0;`” – cremno Jul 14 '15 at 15:55

2 Answers2

30

In The New C Standard section 5.1.2.2.3 Program termination the author Derek Jones commentary on this lines from the C99 standard:

reaching the } that terminates the main function returns a value of 0

is:

The standard finally having to bow to sloppy existing practices.

Which indicates the rationale was to address poor programming practices with respect to explicitly returning a value from main. Prior to this the status returned was undefined.

He indicates that many implementations already implemented this even in C90, so the fact that this change already reflected common implementation also probably helped.

Shafik Yaghmour
  • 154,301
  • 39
  • 440
  • 740
  • 2
    C89 already required "If the main function executes a return that specifies no value, the termination status returned to the host environment is undefined." So it (at least) wasn't undefined behavior, and there's no difference between C89 and C99 if the host environment doesn't use the exit value. – Potatoswatter Jul 14 '15 at 03:24
12

The official rationale document for C99 scarcely addresses this. It appears that exit(0) became the default for control flow off the end of main because exit(0) was given meaningful portable semantics.

Here are the two relevant sections:

5.1.2.2.1 Program startup

The behavior of the arguments to main, and of the interaction of exit, main and atexit (see §7.20.4.2) has been codified to curb some unwanted variety in the representation of argv strings, and in the meaning of values returned by main.

The specification of argc and argv as arguments to main recognizes extensive prior practice.

argv[argc] is required to be a null pointer to provide a redundant check for the end of the list, also on the basis of common practice.

main is the only function that may portably be declared either with zero or two arguments. (The number of other functions’ arguments must match exactly between invocation and definition.) This special case simply recognizes the widespread practice of leaving off the arguments to main when the program does not access the program argument strings. While many implementations support more than two arguments to main, such practice is neither blessed nor forbidden by the Standard; a program that defines main with three arguments is not strictly conforming (see §J.5.1.).

Command line I/O redirection is not mandated by the Standard, as this was deemed to be a feature of the underlying operating system rather than the C language.

and

7.20.4.3 The exit function

The argument to exit is a status indication returned to the invoking environment. In the UNIX operating system, a value of zero is the successful return code from a program. As usage of C has spread beyond UNIX, exit(0) has often been retained as an idiom indicating successful termination, even on operating systems with different systems of return codes. This usage is thus recognized as standard. There has never been a portable way of indicating a non-successful termination, since the arguments to exit are implementation-defined. The EXIT_FAILURE macro was added to C89 to provide such a capability. EXIT_SUCCESS was added as well.

Aside from calls explicitly coded by a programmer, exit is invoked on return from main. Thus in at least this case, the body of exit cannot assume the existence of any objects with automatic storage duration except those declared in exit.

The Committee considered the addition of _exit, but rejected it based on concerns of incompatible with the POSIX specification upon which it is based. For example, one concern expressed is that _exit was specified as a way to get out of a signal handler without triggering another signal, but that is not actually the way _exit behaves in POSIX environments. The Committee did not wish to give programmers this kind of false hope. (But see §7.20.4.4 for C99.)

Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
  • 8
    *"It appears that `exit(0)` became the default for control flow off the end of main because `exit(0)` was given meaningful portable semantics."* -- That doesn't quite follow. C89/C90 specifies that `exit(0)` (or `return 0;` from `main`) denotes successful termination, but falling off the end of `main` wasn't made equivalent to `return 0;` until C99. – Keith Thompson Jul 13 '15 at 22:51
  • 3
    I appreciate the effort. It seems to explain the motivation between the equivalence of `return 0` and `return EXIT_SUCCESS` but not the further mutation of no return being interpreted as `return 0`. If you see it in there, can you provide some interpretation explaining where you see it? – Edward Jul 14 '15 at 02:12
  • Note that finishing `main()` with `exit(0);` is different from either `return 0;` or simply falling off the end (though the differences seldom matter in practice). Specifically, if you call `exit(0);`, local variables in `main()` still exist, whereas they go out of scope with a `return` (implicit or explicit). One time this could matter is if you were careless and used a local variable as a buffer for a file stream — `setbuf()` or `setvbuf()` — and the file has to be closed by the cleanup code. You have to be trying to run foul of the difference, but it's there. – Jonathan Leffler Feb 24 '17 at 21:29