Omitting Return Statement in C++

Omitting return statement in C++

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.

Can I omit return from main in C?

Yes, as of C99, reaching the } at the end of main returns 0 if the return type of main is compatible with int.

5.1.2.2.3 Program termination

If the return type of the main function is a type compatible with int, a return from the initial call to the main function is equivalent to calling the exit function with the value returned by the main function as its argument;11) reaching the } that terminates the main function returns a value of 0. If the return type is not compatible with int, the termination status returned to the host environment is unspecified.

What if I omit the return type of main function in C?

C89/90 still has the implicit int rule, so main() is equivalent to int main(). By leaving off the return type, you've implicitly defined the return type as int. Some may consider this sloppy, but it's strictly conforming (i.e., involves no implementation defined, undefined or unspecified behavior).

For C99, the implicit int rule has been removed, so main() isn't defined. However, a compiler is only required to "issue a diagnostic" upon encountering a violation of a Shall or Shall not clause -- it's still free to continue compiling after issuing the diagnostic. Exactly what constitutes a diagnostic is implementation defined. As such, all that's needed for gcc to conform in this respect is documentation to say that the warning it issues is to be considered a diagnostic.

Edit: "implicit int" in the C89/90 standard isn't really a single rule in a single place -- it's spread around in a couple of places. The primary one is §6.5.2.1, where it says:

-- int, signed, signed int, or no type specifiers

This is part of a list, where all the items on each line of the list are considered equivalent, so this is saying that (unless otherwise prohibited) lack of a type specifier is equivalent to specifying (signed) int.

For function parameters, there's a separate specification (at §6.7.1) that: "Any parameter that is not declared has type int."

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.

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.

Omitting return statement in a function recursively calling itself

You are correct, there are missing return keywords before the recursive calls to get_node_by_val. In both cases, the function exits without a return statement. Since it not a void function, this has undefined behavior.

The code behaves as expected because the register (or whatever other means appropriate for your system's ABI) used for the return value has been set in the recursive call (actually in the final recursive call) and happens do not modified by the caller until it returns to its own caller, which it does immediately. This behavior is not guaranteed and of course it is very bad practice to rely on it.

You should configure the compiler to issue useful warnings to avoid such silly mistakes: gcc -Wall -Wextra -Werror, clang -Weverything -Werror...

Is omitting return statement undefined behaviour in C89 (aka ANSI C)?

Years ago I actually debugged issues caused by this. It gets even more interesting if you have some code paths with returns and others without.

As @aruisdante surmised in the comments, the behavior exhibited is indeed 'undefined', but the only undefined part is the value returned (it's not like many other 'undefined' situations that may crash the program).

These days this actually amounts to a security risk because the 'undefined' value returned is generally whatever happens to be in the CPU register normally used to return values (or on the stack in some implementations), which could theoretically be used to leak sensitive data.

Is it valid to omit the return statement of a non-void function template that throw

are example 1 and example 2 valid?

Yes.

Or we have UB/ill-formed.

No.

Is it valid to omit the return statement of a non-void function/function template that throw

Yes. A non-void returning function must either throw or return avalue. It cannot do both at the same time.

So is int func(){ int x = 4; throw; return x;} valid

It's valid. But it never returns a value. Everything after the throw is dead code.

implicit return value in C with no explicit return in a function that should return non-void

I compiled with gcc version 4.9.2 on Linux with return-type warning on [-Wreturn-type]
The caller expected a true (in C, interpreted as non-zero) for success and 0 for failure. This is what was happening. Since a function that returns non-void, when called, space is created on the stack for the return value, then context is switched to the callee, and finally, when the control comes back to the caller, context is switched back popping all local variables from stack and keeping the return value there on stack to be popped by the caller after return from callee. Thus, having no explicit return statement caused some value to be returned. That is equivalent to having explicit return statement as ‘return 1;’ or 'return 0;' as appropriate. So, better (of course) would be to have explicit return statement e.g.

int somefn() {
// .. do something ..
if (..somecond..)
return 0; // failure
else
return 1; // success
}

To avoid surprises, I would say, compilers should flag 'no return statement in function returning non-void' as error.



Related Topics



Leave a reply



Submit