C and C++ have different rules.
The language rule in C is that if the closing }
of a function that returns a non-void
value is reached and the caller attempts to use that value, the behavior is undefined. Just falling off the end of the function has well defined behavior as long as the caller doesn't use the value.
It would be possible to require all possible control paths to execute a return
statement before leaving the function, but C traditionally has not required compilers to do that kind of code analysis. (Many compilers will do that analysis anyway and issue a warning if appropriate.)
The main reason for allowing falling off the end of a non-void
function is historical. K&R C (the version described in the 1978 first edition of Kernighan and Ritchie's book, before the 1989 ANSI and 1990 ISO C standard) did not have the void
keyword or type. And prior to the 1999 ISO C standard, C had the "implicit int
" rule, meaning that you could declare or define a function without an explicit return type and it would return an int
result.
In K&R C, if you wanted a function that didn't return a result, you would define it without an explicit return type and simply not return a value:
#include <stdio.h>
do_something() {
printf("Not returning a value\n");
}
int main() {
do_something();
return 0;
}
The function would actually return some garbage int
value which the caller would quietly ignore.
In modern C, you would write:
#include <stdio.h>
void do_something(void) {
printf("Not returning a value\n");
}
int main(void) {
do_something();
}
which guarantees that the caller can't try to use the returned value. As of C89/C90, the language still supported the old style to avoid breaking existing code. When the implicit int
rule was dropped in C99, the requirements on non-void
functions failing to return a value were not changed (and most C99 and later compilers still support the implicit int
rule by default, probably with a warning, so old K&R C code can still be compiled).
In C++, flowing off the end of a function other than a constructor, a destructor, a void
function, or main
results in undefined behavior, regardless of what the caller tries to do with the result.