Issue
Ever since I realized many years ago, that this doesn't produce an error by default (in GCC at least), I've always wondered why?
I understand that you can issue compiler flags to produce a warning, but shouldn't it always be an error? Why does it make sense for a non-void function not returning a value to be valid?
An example as requested in the comments:
#include <stdio.h>
int stringSize()
{
}
int main()
{
char cstring[5];
printf( "the last char is: %c\n", cstring[stringSize()-1] );
return 0;
}
...compiles.
Solution
C99 and C++ standards require non-void
functions to return a value, except main
. The missing return statement in main
will be defined (to return 0
). In C++ it's undefined behaviour if execution actually reaches the end of a non-void
function other than main
, while in C it's only UB if the caller uses the return value.
This means functions can look like they might reach the end without returning a value, but actually can't reach the closing }
. John Kugelman's answer shows some examples, like a noreturn function called from one side of an if
. It's only undefined behaviour if execution actually does get to the end without reaching a return
earlier. The rationale includes that checking if every real code path returns a value is quite difficult (without knowing which functions never return), so it's not illegal to compile a function like your example, only to actually call it like your main
does.
As an extension, at least one compiler (MSVC) allows a return value to be set with inline assembly, but most others still require a return statement in functions that use inline asm
.
From C++11 draft:
§ 6.6.3/2
Flowing off the end of a function [...] results in undefined behavior in a value-returning function.
§ 3.6.1/5
If control reaches the end of
main
without encountering areturn
statement, the effect is that of executingreturn 0;
Note that the behaviour described in C++ 6.6.3/2 is not the same in C.
gcc will give you a warning if you call it with -Wreturn-type option.
-Wreturn-type Warn whenever a function is defined with a return-type that defaults to int. Also warn about any return statement with no return-value in a function whose return-type is not void (falling off the end of the function body is considered returning without a value), and about a return statement with an expression in a function whose return-type is void.
This warning is enabled by -Wall.
Just as a curiosity, look what this code does:
#include <iostream>
int foo() {
int a = 5;
int b = a + 1;
}
int main() { std::cout << foo() << std::endl; } // may print 6
This code has formally undefined behaviour, and in practice it's calling convention and architecture dependent. On one particular system, with one particular compiler, the return value is the result of last expression evaluation, stored in the eax
register of that system's processor, if you disable optimization.
This seems to be a consequence of GCC internals with optimization disabled, because in that case it picks the return-value register if it needs any to implement a statement. With optimization enabled in C++ mode, GCC and clang assume this path of execution is unreachable because it contains undefined behaviour. They don't even emit a ret
instruction, so execution falls into the next function in the .text section. Of course undefined behaviour means that anything could happen.
Answered By - Fernando N. Answer Checked By - Timothy Miller (WPSolving Admin)