How Do C++ Progs Get Their Return Value, When a Return Is Not Specified in the Function

How do C++ progs get their return value, when a return is not specified in the function?

On x86 calling conventions, the return value for integers and pointers is on the EAX register. The following is an example of that:

int func() {
if(0) return 5; // otherwise error C4716: 'func' : must return a value
}
int main() {
int a;
a = func();
}

Compiling with cl.exe /Zi, MSVC++10:

push    ebp
mov ebp, esp
push ecx
call j_?func@@YAHXZ ; func(void)
mov [ebp+a], eax ; assumes eax contains the return value
xor eax, eax
mov esp, ebp
pop ebp
retn

Of course, this is all undefined behavior.

Function returns value without return statement

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.

What does it mean when a function does not return a value?

The potential effects of a function include:

  • Returning a value.
  • Modifying an object, including either objects the function can access through pointers or objects with external linkage.
  • Accessing a volatile object, as above.1
  • Modifying a file (a stream).

So, if a function does not return a value, it can still modify an object, as in:

void SetState(SomeStructure *S, int Value)
{
S->State = Value;
}

or it can modify a stream:

void PrintValue(FILE *Stream, int Value)
{
fprintf(Stream, "%d", Value);
}

You can tell the compiler that a function does not return a value by declaring it with return type void. However, the C standard also permits functions with non-void return types not to return a value. For example, you can have a function that sets or gets a value depending upon a command parameter:

int AccessState(int Command, SomeStructure *S,...)
{
switch (Command)
{
case 0: // Get the state.
return S->Value;
case 1: // Set the state from the optional int parameter following S.
va_list ap;
va_start(ap, S);
S->Value = va_arg(S, int);
va_end(ap);
break;
}
}

In this case, there is no way to tell the compiler that the function sometimes does not return a value, but you do not need to. However, you should tell humans that use and read the code that the function sometimes does and sometimes does not return a value with clear documentation in comments or elsewhere.

Footnote

1 Accessing a volatile object is one way for C programs to do things outside the C standard, such as sending commands or data to physical devices.

why a function with returntype in c works with out return statement?

A function declared to return a value that reaches a path without a return has undefined behavior. You just got unlucky that it appeared to still be returning a semi-plausible value. The compiler assumes that a return is called in all exits from the function and that a return value will be available at a particular location.

In your second example effectively anything can happen, including returning different values each call.

g++ has a warning to detect this problem, and it's highly worth enabling.

C and C++ functions without a return statement

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

Wrong returned value in main function?

It's essentially what @Brandon already said in the comments.

main is supposed to return the exit/error code of the program. In the Unix convention, 0 is used to indicate no error (the error value is "false"). And then positive values are used for indicating that there is an error and what error it was.

Why does a main function without a return statement return value 12?

As swegi says, it's undefined behavior. As Steve Jessop et al say, it's an unspecified value until C89, and specified in C99 (the observed behavior is non-conformant to C99)

What actually happens in most environments is that the return value from the last printf is left in the register used for return values.

So it'll be 11 for n == 0, 12 if n is one digit, 14 for two digit n, 16 for three digit n, etc.



Related Topics



Leave a reply



Submit