Function returns value without return statement
Why does fol开发者_Python百科lowing 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.
精彩评论