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

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.

Related

Why missing return statement isn't treated as an error? [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).

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

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

Why do compilers give a warning about returning a reference to a local stack variable if it is undefined behaviour?

The C++ standard states that returning reference to a local variable (on the stack) is undefined behaviour, so why do many (if not all) of the current compilers only give a warning for doing so?
struct A{
};
A& foo()
{
A a;
return a; //gcc and VS2008 both give this a warning, but not a compiler error
}
Would it not be better if compilers give a error instead of warning for this code?
Are there any great advantages to allowing this code to compile with just a warning?
Please note that this is not about a const reference which could lengthen the lifetime of the temporary to the lifetime of the reference itself.
It is almost impossible to verify from a compiler point of view whether you are returning a reference to a temporary. If the standard dictated that to be diagnosed as an error, writing a compiler would be almost impossible. Consider:
bool not_so_random() { return true; }
int& foo( int x ) {
static int s = 10;
int *p = &s;
if ( !not_so_random() ) {
p = &x;
}
return *p;
}
The above program is correct and safe to run, in our current implementation it is guaranteed that foo will return a reference to a static variable, which is safe. But from a compiler perspective (and with separate compilation in place, where the implementation of not_so_random() is not accessible, the compiler cannot know that the program is well-formed.
This is a toy example, but you can imagine similar code, with different return paths, where p might refer to different long-lived objects in all paths that return *p.
Undefined behaviour is not a compilation error, it's just not a well-formed C++ program. Not every ill-formed program is incompilable, it's just un-predictable. I'd wager a bet that it's not even possible in principle for a computer to decide whether a given program text is a well-formed C++ program.
You can always add -Werror to gcc to make warnings terminate compilation with an error!
To add another favourite SO topic: Would you like ++i++ to cause a compile error, too?
If you return a pointer/reference to a local inside function the behavior is well defined as long as you do not dereference the pointer/reference returned from the function.
It is an Undefined Behavior only when one derefers the returned pointer.
Whether it is a Undefined Behavior or not depends on the code calling the function and not the function itself.
So just while compiling the function, the compiler cannot determine if the behavior is Undefined or Well Defined. The best it can do is to warn you of a potential problem and it does!
An Code Sample:
#include <iostream>
struct A
{
int m_i;
A():m_i(10)
{
}
};
A& foo()
{
A a;
a.m_i = 20;
return a;
}
int main()
{
foo(); //This is not an Undefined Behavior, return value was never used.
A ref = foo(); //Still not an Undefined Behavior, return value not yet used.
std::cout<<ref.m_i; //Undefined Behavior, returned value is used.
return 0;
}
Reference to the C++ Standard:
section 3.8
Before the lifetime of an object has started but after the storage which the object will occupy has been allo-cated 34) or, after the lifetime of an object has ended and before the storage which the object occupied is reused or released, any pointer that refers to the storage location where the object will be or was located may be used but only in limited ways. Such a pointer refers to allocated storage (3.7.3.2), and using the
pointer as if the pointer were of type void*, is well-defined. Such a pointer may be dereferenced but the resulting lvalue may only be used in limited ways, as described below. If the object will be or was of a class type with a non-trivial destructor, and the pointer is used as the operand of a delete-expression, the program has undefined behavior. If the object will be or was of a non-POD class type, the program has undefined behavior if:
— .......
Because standard does not restrict us.
If you want to shoot to your own foot you can do it!
However lets see and example where it can be useful:
int &foo()
{
int y;
}
bool stack_grows_forward()
{
int &p=foo();
int my_p;
return &my_p < &p;
}
Compilers should not refuse to compile programs unless the standard says they are allowed to do so. Otherwise it would be much harder to port programs, since they might not compile with a different compiler, even though they comply with the standard.
Consider the following function:
int foobar() {
int a=1,b=0;
return a/b;
}
Any decent compiler will detect that I am dividing by zero, but it should not reject the code since I might actually want to trigger a SIG_FPE signal.
As David Rodríguez has pointed out, there are some cases which are undecidable but there are also some which are not. Some new version of the standard might describe some cases where the compiler must/is allowed to reject programs. That would require the standard to be very specific about the static analysis which is to be performed.
The Java standard actually specifies some rules for checking that non-void methods always return a value. Unfortunately I haven't read enough of the C++ standard to know what the compiler is allowed to do.
You could also return a reference to a static variable, which would be valid code so the code must be able to compile.
It's pretty much super-bad practice to rely on this, but I do believe that in many cases (and that's never a good wager), that memory reference would still be valid if no functions are called between the time foo() returns and the time the calling function uses its return value. In that case, that area of the stack would not have an opportunity to get overwritten.
In C and C++ you can choose to access arbitrary sections of memory anyway (within the process's memory space, of course) via pointer arithmetic, so why not allow the possibility of constructing a reference to wherever one so chooses?

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