While looking through code at work I found some (seemingly) offensive code in which a function had a return type, but no return. I knew the code worked, but assumed it was just a bug in the compiler.
I wrote the following test and ran it using my compiler (gcc (Homebrew gcc 5.2.0) 5.2.0)
#include <stdio.h>
int f(int a, int b) {
int c = a + b;
}
int main() {
int x = 5, y = 6;
printf("f(%d,%d) is %d\n", x, y, f(x,y)); // f(5,6) is 11
return 0;
}
Analogous to the code I found at work, this defaults to returning the result of the last expression executed in the function.
I found this question, but was not satisfied with the answer. I know that with -Wall -Werror
this behavior can be avoided, but why is it an option? Why is this still allowed?
If no return statement appears in a function definition, control automatically returns to the calling function after the last statement of the called function is executed. In this case, the return value of the called function is undefined.
If you do not specify a return type or parameter type, C will implicitly declare it as int .
In the example above,the function returns an int. Some languages differentiate between "subroutines", which do not return a value, and "functions", which do. In C there are no subroutines, only functions, but functions are not required to return a value.
In lieu of a data type, void functions use the keyword "void." A void function performs a task, and then control returns back to the caller--but, it does not return a value. You may or may not use the return statement, as there is no return value.
"Why is this still allowed?" It is not, but in general, the compiler cannot prove you are doing it. Consider this (of course extremely simplified) example:
// Input is always true because logic reason
int fun (bool b) {
if (b) {
return 7;
}
}
Or even this one:
int fun (bool b) {
if (b) {
return 7;
}
// Defined in a different translation unit, will always call exit()
foo();
// Now we can never get here, but the compiler cannot know
}
Now the first example could flow off the end, but it never will as long as the function is used "properly"; and the second one could not, but the compiler cannot know this. So the compiler would break "working" and legal, although probably stupid, code by making this an error.
Now the example you posted is a little different: Here, all paths flow off the end, so the compiler could reject or just ignore this function. It would however break real world code that relies on the compiler specific behavior as in your production code, and people do not like that, even if they are wrong.
But in the end, flowing off the end of a non-void
function still is undefined behavior. It might work on certain compilers, but it is not and never was guaranteed to.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With