Why missing return statement isn't treated as an error? [duplicate] - c++

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.

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 a return statement, the effect is that of executing
return 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.

gcc does not by default check that all code paths return a value because in general this cannot be done. It assumes you know what you are doing. Consider a common example using enumerations:
Color getColor(Suit suit) {
switch (suit) {
case HEARTS: case DIAMONDS: return RED;
case SPADES: case CLUBS: return BLACK;
}
// Error, no return?
}
You the programmer know that, barring a bug, this method always returns a color. gcc trusts that you know what you are doing so it doesn't force you to put a return at the bottom of the function.
javac, on the other hand, tries to verify that all code paths return a value and throws an error if it cannot prove that they all do. This error is mandated by the Java language specification. Note that sometimes it is wrong and you have to put in an unnecessary return statement.
char getChoice() {
int ch = read();
if (ch == -1 || ch == 'q') {
System.exit(0);
}
else {
return (char) ch;
}
// Cannot reach here, but still an error.
}
It's a philosophical difference. C and C++ are more permissive and trusting languages than Java or C# and so some errors in the newer languages are warnings in C/C++ and some warnings are ignored or off by default.

You mean, why flowing off the end of a value-returning function (i.e. exiting without an explicit return) is not an error?
Firstly, in C whether a function returns something meaningful or not is only critical when the executing code actually uses the returned value. Maybe the language didn't want to force you to return anything when you know that you are not going to use it anyway most of the time.
Secondly, apparently the language specification did not want to force the compiler authors to detect and verify all possible control paths for the presence of an explicit return (although in many cases this is not that difficult to do). Also, some control paths might lead into to non-returning functions - the trait that is generally non known to the compiler. Such paths can become a source of annoying false positives.
Note also, that C and C++ differ in their definitions of the behavior in this case. In C++ just flowing off the end of a value returning function is always undefined behavior (regardless of whether the function's result is used by the calling code). In C this causes undefined behavior only if the calling code tries to use the returned value.

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.

It is legal under C/C++ to not return from a function that claims to return something. There are a number of use cases, such as calling exit(-1), or a function that calls it or throws an exception.
The compiler is not going to reject legal C++ even if it leads to UB if you are asking it not to. In particular, you are asking for no warnings to be generated. (Gcc still turns on some by default, but when added those seem to align with new features not new warnings for old features)
Changing the default no-arg gcc to emit some warnings could be a breaking change for existing scripts or make systems. Well designed ones either -Wall and deal with warnings, or toggle individual warnings.
Learning to use a C++ tool chain is a barrier to learning to be a C++ programmer, but C++ tool chains are typically written by and for experts.

I believe this is because of legacy code (C never required return statement so did C++). There is probably huge code base relying on that "feature". But at least there is -Werror=return-type
flag on many compilers (including gcc and clang).

In some limited and rare cases, flowing off the end of a non-void function without returning a value could be useful. Like the following MSVC-specific code:
double pi()
{
__asm fldpi
}
This function returns pi using x86 assembly. Unlike assembly in GCC, I know of no way to use return to do this without involving overhead in the result.
As far as I know, mainstream C++ compilers should emit at least warnings for apparently invalid code. If I make the body of pi() empty, GCC/Clang will report a warning, and MSVC will report an error.
People mentioned exceptions and exit in some answers. Those are not valid reasons. Either throwing an exception, or calling exit, will not make the function execution flow off the end. And the compilers know it: writing a throw statement or calling exit in the empty body of pi() will stop any warnings or errors from a compiler.

Under what circumstances doesn't it produce an error? If it declares a return type and doesn't return something, it sounds like an error to me.
The one exception I can think of is the main() function, which doesn't need a return statement at all (at least in C++; I don't have either of the C standards handy). If there is no return, it will act as if return 0; is the last statement.

I was getting that warning because i forgot to add the statement
itr = itr ->currentNode;
basically missing that statement, function get into infinte loop and was never returning a value, That's the reason i was getting that warning during the compilation time
void* list_get(list* lst, int idx){
node* itr = lst->head;
if (idx >= lst->size){
printf("list out of index");
exit(1);
}
while(itr != NULL){
if(itr->index == idx){
return itr->element;
}
itr = itr->currentNode;
}
}

Sounds like you need to turn up your compiler warnings:
$ gcc -Wall -Wextra -Werror -x c -
int main(void) { return; }
cc1: warnings being treated as errors
<stdin>: In function ‘main’:
<stdin>:1: warning: ‘return’ with no value, in function returning non-void
<stdin>:1: warning: control reaches end of non-void function
$

It is a constraint violation in c99, but not in c89. Contrast:
c89:
3.6.6.4 The return statement
Constraints
A return statement with an expression shall not appear in a
function whose return type is void .
c99:
6.8.6.4 The return statement
Constraints
A return statement with an expression shall not appear in a function whose return type is void. A return statement without an expression shall only appear in a function whose return type is void.
Even in --std=c99 mode, gcc will only throw a warning (although without needing to enable additional -W flags, as is required by default or in c89/90).
Edit to add that in c89, "reaching the } that terminates a function is equivalent to
executing a return statement without an expression" (3.6.6.4). However, in c99 the behavior is undefined (6.9.1).

Related

Function returns wrong value but is able to print the correct value in a simple program to count number of steps needed to reach a point [duplicate]

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.
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 a return statement, the effect is that of executing
return 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.
gcc does not by default check that all code paths return a value because in general this cannot be done. It assumes you know what you are doing. Consider a common example using enumerations:
Color getColor(Suit suit) {
switch (suit) {
case HEARTS: case DIAMONDS: return RED;
case SPADES: case CLUBS: return BLACK;
}
// Error, no return?
}
You the programmer know that, barring a bug, this method always returns a color. gcc trusts that you know what you are doing so it doesn't force you to put a return at the bottom of the function.
javac, on the other hand, tries to verify that all code paths return a value and throws an error if it cannot prove that they all do. This error is mandated by the Java language specification. Note that sometimes it is wrong and you have to put in an unnecessary return statement.
char getChoice() {
int ch = read();
if (ch == -1 || ch == 'q') {
System.exit(0);
}
else {
return (char) ch;
}
// Cannot reach here, but still an error.
}
It's a philosophical difference. C and C++ are more permissive and trusting languages than Java or C# and so some errors in the newer languages are warnings in C/C++ and some warnings are ignored or off by default.
You mean, why flowing off the end of a value-returning function (i.e. exiting without an explicit return) is not an error?
Firstly, in C whether a function returns something meaningful or not is only critical when the executing code actually uses the returned value. Maybe the language didn't want to force you to return anything when you know that you are not going to use it anyway most of the time.
Secondly, apparently the language specification did not want to force the compiler authors to detect and verify all possible control paths for the presence of an explicit return (although in many cases this is not that difficult to do). Also, some control paths might lead into to non-returning functions - the trait that is generally non known to the compiler. Such paths can become a source of annoying false positives.
Note also, that C and C++ differ in their definitions of the behavior in this case. In C++ just flowing off the end of a value returning function is always undefined behavior (regardless of whether the function's result is used by the calling code). In C this causes undefined behavior only if the calling code tries to use the returned value.
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.
It is legal under C/C++ to not return from a function that claims to return something. There are a number of use cases, such as calling exit(-1), or a function that calls it or throws an exception.
The compiler is not going to reject legal C++ even if it leads to UB if you are asking it not to. In particular, you are asking for no warnings to be generated. (Gcc still turns on some by default, but when added those seem to align with new features not new warnings for old features)
Changing the default no-arg gcc to emit some warnings could be a breaking change for existing scripts or make systems. Well designed ones either -Wall and deal with warnings, or toggle individual warnings.
Learning to use a C++ tool chain is a barrier to learning to be a C++ programmer, but C++ tool chains are typically written by and for experts.
I believe this is because of legacy code (C never required return statement so did C++). There is probably huge code base relying on that "feature". But at least there is -Werror=return-type
flag on many compilers (including gcc and clang).
In some limited and rare cases, flowing off the end of a non-void function without returning a value could be useful. Like the following MSVC-specific code:
double pi()
{
__asm fldpi
}
This function returns pi using x86 assembly. Unlike assembly in GCC, I know of no way to use return to do this without involving overhead in the result.
As far as I know, mainstream C++ compilers should emit at least warnings for apparently invalid code. If I make the body of pi() empty, GCC/Clang will report a warning, and MSVC will report an error.
People mentioned exceptions and exit in some answers. Those are not valid reasons. Either throwing an exception, or calling exit, will not make the function execution flow off the end. And the compilers know it: writing a throw statement or calling exit in the empty body of pi() will stop any warnings or errors from a compiler.
Under what circumstances doesn't it produce an error? If it declares a return type and doesn't return something, it sounds like an error to me.
The one exception I can think of is the main() function, which doesn't need a return statement at all (at least in C++; I don't have either of the C standards handy). If there is no return, it will act as if return 0; is the last statement.
I was getting that warning because i forgot to add the statement
itr = itr ->currentNode;
basically missing that statement, function get into infinte loop and was never returning a value, That's the reason i was getting that warning during the compilation time
void* list_get(list* lst, int idx){
node* itr = lst->head;
if (idx >= lst->size){
printf("list out of index");
exit(1);
}
while(itr != NULL){
if(itr->index == idx){
return itr->element;
}
itr = itr->currentNode;
}
}
Sounds like you need to turn up your compiler warnings:
$ gcc -Wall -Wextra -Werror -x c -
int main(void) { return; }
cc1: warnings being treated as errors
<stdin>: In function ‘main’:
<stdin>:1: warning: ‘return’ with no value, in function returning non-void
<stdin>:1: warning: control reaches end of non-void function
$
It is a constraint violation in c99, but not in c89. Contrast:
c89:
3.6.6.4 The return statement
Constraints
A return statement with an expression shall not appear in a
function whose return type is void .
c99:
6.8.6.4 The return statement
Constraints
A return statement with an expression shall not appear in a function whose return type is void. A return statement without an expression shall only appear in a function whose return type is void.
Even in --std=c99 mode, gcc will only throw a warning (although without needing to enable additional -W flags, as is required by default or in c89/90).
Edit to add that in c89, "reaching the } that terminates a function is equivalent to
executing a return statement without an expression" (3.6.6.4). However, in c99 the behavior is undefined (6.9.1).

int function returns value also without the return [duplicate]

Why does following code has a correct output? int GGT has no return statement, but the code does work anyway? There are no global variables set.
#include <stdio.h>
#include <stdlib.h>
int GGT(int, int);
void main() {
int x1, x2;
printf("Bitte geben Sie zwei Zahlen ein: \n");
scanf("%d", &x1);
scanf("%d", &x2);
printf("GGT ist: %d\n", GGT(x1, x2));
system("Pause");
}
int GGT(int x1, int x2) {
while(x1 != x2) {
if(x1 > x2) {
/*return*/ x1 = x1 - x2;
}
else {
/*return*/ x2 = x2 - x1;
}
}
}
For x86 at least, the return value of this function should be in eax register. Anything that was there will be considered to be the return value by the caller.
Because eax is used as return register, it is often used as "scratch" register by callee, because it does not need to be preserved. This means that it's very possible that it will be used as any of local variables. Because both of them are equal at the end, it's more probable that the correct value will be left in eax.
It should not work and certainly do not work on all compilers and target OS, even if it works on yours.
The likely explanation is that a function returning int always return something, and it's usually the content of a register. It probably happens that the register used for return value is in your case the same used to compute the last expression before returning from the function (on x86 targets, certainly eax).
This being said, an optimizing compiler detecting that there is no return is allowed to completely remove the code of this function. Henceforth the effect you see (may) disappear when activating higher optimizations levels.
I tested it with gcc:
gcc without optimization:
inputs 10, 20 -> result is 10
gcc -O1
inputs 10, 20 -> result is 1
gcc -O2
inputs 10, 20 -> result is 0
If a function is defined to return a value but does not, and the calling function attempts to use the return value, you invoke undefined behavior.
This is spelled out in section 6.9.1p12 of the C standard:
If the } that terminates a function is reached, and the value of the
function call is used by the caller, the behavior is undefined.
You got "lucky" in this case that the program appeared to work properly, but there's no guarantee of that. Had you compiled with different optimization settings or a different compiler altogether you could end up with different results.
So the moral of the story: if the function says it returns a value, always return a value.
On x86 the return value is stored in EAX register, which "accidentally" is also used by this compiler to store the result of arithmetic operations (or at least subtraction). You can check this by looking at assembly generated by your compiler. I agree with kriss - you can't assume this will always be the case, so it's better to explicitly specify the return value.
Official verbiage:
6.9.1 Function definitions
...
12 If the } that terminates a function is reached, and the value of the function call is used by
the caller, the behavior is undefined.
where "undefined benavior" means:
1 undefined behavior
behavior, upon use of a nonportable or erroneous program construct or of erroneous data,
for which this International Standard imposes no requirements
2 NOTE Possible undefined behavior ranges from ignoring the situation completely with unpredictable
results, to behaving during translation or program execution in a documented manner characteristic of the
environment (with or without the issuance of a diagnostic message), to terminating a translation or
execution (with the issuance of a diagnostic message).
3 EXAMPLE An example of undefined behavior is the behavior on integer overflow.
C 2011 Online Draft
Believe it or not, a function typed something other than void is not required to have a return statement. It's not enforced by the language grammar, and there is no constraint that a non-void function must contain a return statement. The only constraints are that, if it is present, a return statement in a void function not return the value of any expression, and that a return statement in a non-void function must return the value of an expression.
Why is that the case?
C initially did not have a void data type, and there was no way to specify a subroutine that was only executed for its side effects and didn't return a value. There was no good way to return "nothing", so the return statement was not required. C also at this time had "implicit int" declarations - you could define a function body without a type, and the compiler would assume it was typed int:
foo( a, b ) // old style parameter declarations
int a; // still legal, but no longer really used
char *b; // for very good reasons
{
// do something interesting with a and b
}
foo is implicitly typed to return int, even if no value is explicitly being returned. This is okay as long as the caller doesn't try to use foo's non-existent return value. So a convention sort of developed where "procedures" (functions executed solely for side effects) were not explicitly typed, and had no return statement.
Because legacy code is forever, the behavior with respect to return statements hasn't been changed in more recent versions of the C standard, even though implicit int declarations were removed in C99.
GCC pastes "ret" instruction in such case, while clang pastes "ud2" and app crashes at run-time.

Why function with return value can return nothing? [duplicate]

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.
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 a return statement, the effect is that of executing
return 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.
gcc does not by default check that all code paths return a value because in general this cannot be done. It assumes you know what you are doing. Consider a common example using enumerations:
Color getColor(Suit suit) {
switch (suit) {
case HEARTS: case DIAMONDS: return RED;
case SPADES: case CLUBS: return BLACK;
}
// Error, no return?
}
You the programmer know that, barring a bug, this method always returns a color. gcc trusts that you know what you are doing so it doesn't force you to put a return at the bottom of the function.
javac, on the other hand, tries to verify that all code paths return a value and throws an error if it cannot prove that they all do. This error is mandated by the Java language specification. Note that sometimes it is wrong and you have to put in an unnecessary return statement.
char getChoice() {
int ch = read();
if (ch == -1 || ch == 'q') {
System.exit(0);
}
else {
return (char) ch;
}
// Cannot reach here, but still an error.
}
It's a philosophical difference. C and C++ are more permissive and trusting languages than Java or C# and so some errors in the newer languages are warnings in C/C++ and some warnings are ignored or off by default.
You mean, why flowing off the end of a value-returning function (i.e. exiting without an explicit return) is not an error?
Firstly, in C whether a function returns something meaningful or not is only critical when the executing code actually uses the returned value. Maybe the language didn't want to force you to return anything when you know that you are not going to use it anyway most of the time.
Secondly, apparently the language specification did not want to force the compiler authors to detect and verify all possible control paths for the presence of an explicit return (although in many cases this is not that difficult to do). Also, some control paths might lead into to non-returning functions - the trait that is generally non known to the compiler. Such paths can become a source of annoying false positives.
Note also, that C and C++ differ in their definitions of the behavior in this case. In C++ just flowing off the end of a value returning function is always undefined behavior (regardless of whether the function's result is used by the calling code). In C this causes undefined behavior only if the calling code tries to use the returned value.
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.
It is legal under C/C++ to not return from a function that claims to return something. There are a number of use cases, such as calling exit(-1), or a function that calls it or throws an exception.
The compiler is not going to reject legal C++ even if it leads to UB if you are asking it not to. In particular, you are asking for no warnings to be generated. (Gcc still turns on some by default, but when added those seem to align with new features not new warnings for old features)
Changing the default no-arg gcc to emit some warnings could be a breaking change for existing scripts or make systems. Well designed ones either -Wall and deal with warnings, or toggle individual warnings.
Learning to use a C++ tool chain is a barrier to learning to be a C++ programmer, but C++ tool chains are typically written by and for experts.
I believe this is because of legacy code (C never required return statement so did C++). There is probably huge code base relying on that "feature". But at least there is -Werror=return-type
flag on many compilers (including gcc and clang).
In some limited and rare cases, flowing off the end of a non-void function without returning a value could be useful. Like the following MSVC-specific code:
double pi()
{
__asm fldpi
}
This function returns pi using x86 assembly. Unlike assembly in GCC, I know of no way to use return to do this without involving overhead in the result.
As far as I know, mainstream C++ compilers should emit at least warnings for apparently invalid code. If I make the body of pi() empty, GCC/Clang will report a warning, and MSVC will report an error.
People mentioned exceptions and exit in some answers. Those are not valid reasons. Either throwing an exception, or calling exit, will not make the function execution flow off the end. And the compilers know it: writing a throw statement or calling exit in the empty body of pi() will stop any warnings or errors from a compiler.
Under what circumstances doesn't it produce an error? If it declares a return type and doesn't return something, it sounds like an error to me.
The one exception I can think of is the main() function, which doesn't need a return statement at all (at least in C++; I don't have either of the C standards handy). If there is no return, it will act as if return 0; is the last statement.
I was getting that warning because i forgot to add the statement
itr = itr ->currentNode;
basically missing that statement, function get into infinte loop and was never returning a value, That's the reason i was getting that warning during the compilation time
void* list_get(list* lst, int idx){
node* itr = lst->head;
if (idx >= lst->size){
printf("list out of index");
exit(1);
}
while(itr != NULL){
if(itr->index == idx){
return itr->element;
}
itr = itr->currentNode;
}
}
Sounds like you need to turn up your compiler warnings:
$ gcc -Wall -Wextra -Werror -x c -
int main(void) { return; }
cc1: warnings being treated as errors
<stdin>: In function ‘main’:
<stdin>:1: warning: ‘return’ with no value, in function returning non-void
<stdin>:1: warning: control reaches end of non-void function
$
It is a constraint violation in c99, but not in c89. Contrast:
c89:
3.6.6.4 The return statement
Constraints
A return statement with an expression shall not appear in a
function whose return type is void .
c99:
6.8.6.4 The return statement
Constraints
A return statement with an expression shall not appear in a function whose return type is void. A return statement without an expression shall only appear in a function whose return type is void.
Even in --std=c99 mode, gcc will only throw a warning (although without needing to enable additional -W flags, as is required by default or in c89/90).
Edit to add that in c89, "reaching the } that terminates a function is equivalent to
executing a return statement without an expression" (3.6.6.4). However, in c99 the behavior is undefined (6.9.1).

If a function returns no value, with a valid return type, is it okay to for the compiler to return garbage?

If a function has a return type other than void, and the function does not return anything, then I guess the compiler returns a garbage value (possibly seen as an uninitialized value). It happens at compile time, so why shouldn't it show an error?
For example,
int func1() {
return; // error
}
int func2() {
// does not return anything
}
The second func2 should throw an error, but it does not. Is there a reason for it? My thinking was such that, it can be seen as an uninitialized value, so if we need to throw an error in the second case, then we need to throw error, if an value is uninitialized, say
int i; // error
int i = 6; // okay
Any thoughts, or is this a duplicate question? I appreciate your help.
In C++, such code has undefined behaviour:
[stmt.return]/2 ... Flowing off the end of a function is equivalent to a return with no value; this results in undefined behavior in a value-returning function. ...
Most compilers will produce a warning for code similar to that in the question.
The C++ standard does not require this to be a compile time error because in the general case it would be very difficult to correctly determine whether the code actually runs off the end of the function, or if the function exits through an exception (or a longjmp or similar mechanism).
Consider
int func3() {
func4();
}
If func4() throws, then this code is totally fine. The compiler might not be able to see the definition of func4() (because of separate compilation), and so cannot know whether it will throw or not.
Furthermore, even if the compiler can prove that func4() does not throw, it would still have to prove that func3() actually gets called before it could legitimately reject the program. Such analysis requires inspection of the entire program, which is incompatible with separate compilation, and which is not even possible in the general case.
In C, quoting N1256 6.9.1p12:
If the } that terminates a function is reached, and the value of the
function call is used by the caller, the behavior is undefined.
So it's legal (but a bad idea) for a non-void function to fail to return a value, but if it does so and the caller attempts to use the result, the behavior is undefined. Note that it doesn't necessarily just return some arbitrary value; as far as the standard is concerned, anything is possible.
Pre-ANSI C didn't have the void keyword, so the way to write a function that didn't return a value was to leave out the return type, making it implicitly return int. Requiring a return statement in a value-returning function would have broken old code. It would also have required extra analysis by the compiler to determine that all code paths hit a return statement; such analysis is reasonable for modern compilers, but might have been an excessive burden when C was first standardized.
C++ is slightly more strict. In C++:
Flowing off the end of a function is equivalent to a return with
no value; this results in undefined behavior in a value-returning
function.
so the behavior is undefined whether the caller attempts to use the (nonexistent) result or not.
C and C++ compilers certainly can warn about missing return statements, or about control paths that fall off the end of a function without executing a return statement, but the respective standards do not require them to do so.
In C, it is actually legal for a non-void function to finish without returning a value, as long as the calling code doesn't try to use the return value.
On the other hand a return statement without an expression is not allowed to appear in a non-void function.
The relevant parts of the C99 standard are §6.9.1 for the first case:
If the } that terminates a function is reached, and the value of the
function call is used by the caller, the behavior is undefined.
and §6.8.6.4 for the second case:
A return statement without an expression shall only appear in a
function whose return type is void.
Both of your functions are ill formed. The difference between them is that your func1 violates the rules about how the return statement can be used while your func2 is undefined behavior. The return statement in your func1 is illegal and an implementation must diagnose this. The lack of a return statement in your func2 is undefined behavior. Most compilers will diagnose this, but none have to.

Omitting return statement in C++

I just had some weird behavior from a version of g++ for Windows that I got with Strawberry Perl. It allowed me to omit a return statement.
I have a member function that returns a structure consisting of two pointers, called a boundTag:
struct boundTag Box::getBound(int side) {
struct boundTag retBoundTag;
retBoundTag.box = this;
switch (side)
{
// set retBoundTag.bound based on value of "side"
}
}
This function gave me some bad output, and I discovered that it had no return statement. I had meant to return retBoundTag but forgot to actually write the return statement. Once I added return retBoundTag; everything was fine.
But I had tested this function and gotten correct boundTag output from it. Even now, when I remove the return statement, g++ compiles it without warning. WTF? Does it guess to return retBoundTag?
Omitting the return statement in a non-void function [Except main()] and using the returned value in your code invokes Undefined Behaviour.
ISO C++-98[Section 6.6.3/2]
A return statement with an expression can be used
only in functions returning a value; the value of the expression is
returned to the caller of the function. If required, the expression
is implicitly converted to the return type of the function in which it
appears. A return statement can involve the construction and copy of
a temporary object (class.temporary). Flowing off the end of a
function is equivalent to a return with no value; this results in
undefined behavior in a value-returning function.
For example
int func()
{
int a=10;
//do something with 'a'
//oops no return statement
}
int main()
{
int p=func();
//using p is dangerous now
//return statement is optional here
}
Generally g++ gives a warning: control reaches end of non-void function. Try compiling with -Wall option.
C and C++ don't require you to have a return statement.
It might not be necessary to have one, because the function enters an infinite loop, or because it throws an exception.
Prasoon already quoted the relevant part of the standard:
[Section 6.6.3/2]
A return statement with an expression can be used only in functions returning a value; the value of the expression is returned to the caller of the function. If required, the expression is implicitly converted to the return type of the function in which it appears. A return statement can involve the construction and copy of a temporary object (class.temporary). Flowing off the end of a function is equivalent to a return with no value; this results in undefined behavior in a value-returning function.
What it means is that not having a return statement is ok. But reaching the end of the function without returning is undefined behavior.
The compiler can't always detect these cases, so it's not required to be a compile error (it'd have to solve the halting problem to determine whether execution ever actually reaches the end of the function). It is simply undefined what should happen if this occurs. It might appear to work (because the calling function will just look at whatever garbage value is in the location where the return value is supposed to be), it might crash, or make demons fly out of your nose.
Even though aC++ compiler can't always detect when a function can't execute a return statement, it usually can.
On the bright side, at least g++ makes this easy to detect with the command-line compiler option "-Wreturn-type". You just need to remember to enable it. (It also gets enabled if you use "-Wall".)