20

My Herb Schildt book on C++ says: "... In C++, if a function is declared as returning a value, it must return a value." However, if I write a function with a non-void return type and do not return anything, the compiler issues a warning instead of an error: "Control reaches end of non-void function."

I use gcc (MinGW) and have set the -pedantic flag.

AlwaysLearning
  • 201
  • 1
  • 2
  • 3
  • 18
    I heard that Herb Schildt books are bad. – Johannes Schaub - litb May 06 '10 at 20:09
  • 8
    Yes, it's mandatory. Also, think about getting a better book. Most of Schildt's books are generally considered bad. – sellibitze May 06 '10 at 20:09
  • That’s why I compile with `-Werror` … – Konrad Rudolph May 06 '10 at 20:17
  • 1
    related : http://stackoverflow.com/questions/1610030/why-can-you-return-from-a-non-void-function-without-returning-a-value-without-pro – Tom May 06 '10 at 20:17
  • Evidently -Werror is not a solution here. – AlwaysLearning May 06 '10 at 20:22
  • I wonder how complicated it would be to have a compiler put a segfault or something at the end of non-void functions instead of a return statement. Not something I'd want in production code, but it would be a nice balance between not compiling and silently failing while debugging. – Dennis Zickefoose May 06 '10 at 20:40
  • Yet another reason why C++ sucks due to backwards compatibility with C, IMHO. IIRC, VC++ warns by default on this. GCC definitely warns with -Wall specified, but I don't think it does by default (at least on earlier versions). Currently, I build my platform agnostic code w/ GCC & then PC and I've found that compiler options `-Wall -Wextra` in GCC give a good set of warnings that ought not be ignored (without at least understanding why they're being raised). – Nathan Ernst May 06 '10 at 23:48
  • @Konrad, `-Werror` would be nice, but it's not always possible (3rd party libs, etc). Boost, ACE, RW all generate warnings, and I've had no luck getting GCC to treat them as system headers. I do, however treat warning free code as a goal. Personally, I strive for my own code to be warning free, or at least explicitly suppress warnings I generated and know I can safely ignore - this is typically only on Windows and deals with DLL export issues. – Nathan Ernst May 06 '10 at 23:53
  • Entertaining takedown of a Herb Schildt book - http://www.seebs.net/c/c_tcn4e.html – jon hanson May 07 '10 at 06:13
  • @Nathan Ernst: I **always** use `-Werror` nowadays. The trick is to include 3rd party libs via `-isystem` instead of `-I` on the command line to mark them as system headers. This excludes them from diagnostics. Thus you can safely compile with warnings as errors. – Konrad Rudolph May 07 '10 at 09:23
  • @AlwaysLearning: Why not? The code that triggers this warning is definitely UB according to the standard so it’s a good thing to make it fail compilation. – Konrad Rudolph May 07 '10 at 09:25
  • @Konrad Rudolph, I (briefly) tried experimenting with -isystem the other week and I had no success getting it to work... I'll have to revisit. – Nathan Ernst May 07 '10 at 21:42

7 Answers7

27

§6.6.3/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.

So it depends on your definition of mandatory. Do you have to? No. But if you want your program to have well-defined behavior, yes.*

*main is an exception, see §3.6.1/5. If control reaches the end of main without a return, it will have the effect of return 0;.

GManNickG
  • 494,350
  • 52
  • 494
  • 543
  • 5
    Undefined behavior is far worse than a crash. – György Andrasek May 06 '10 at 20:15
  • 2
    @Jurily: I agree, but I don't see how that's related to anything here. – GManNickG May 06 '10 at 20:17
  • 2
    Note the wording: it applies to execution, not compilation. If you enter a function with a return type other than `void`, and do not flow off the end, you don't need a `return` to avoid undefined behavior. – David Thornley May 06 '10 at 20:24
  • 1
    @Jurily, really? Undefined behavior could mean that it decides to format your hard drive, spam your boss with child pornography and CC the FBI on the email. Undefined behavior means it can do *anything* after that point, up to, including, and even exceeding being a complete an utter asshole. You're best failing to a known state. At least if it's crashed, I know it's *stopped* doing bad things. – Nathan Ernst May 06 '10 at 23:57
11

It is mandatory--it is an undefined behavior when such function ends without returning anything (so compilers might actually implement some kind of special behaviour). However, there are some special cases.

::main is an exception, it is assumed that return 0; is at the end of its code.

Also, you don't have to return a value in a function that does not return cleanly, f.e.:

int Foo() {
    throw 42;
}
liori
  • 40,917
  • 13
  • 78
  • 105
  • 3
    The exception example is probably why this is just a warning. Compilers aren't very good at knowing which control paths are actually used, and an error would result in a lot of perfectly good code getting rejected. – Dennis Zickefoose May 06 '10 at 20:19
  • @DennisZickefoose - it is "just a warning" because the behaviour of returning from a function by falling off the end gives undefined behaviour (other than `main()`). A diagnostic is not required when behaviour is undefined (although compilers MAY elect to give warnings anyway - that is a quality of implementation concern, not a requirement of the standard). In any event, there are plenty of other cases where a compiler can't reliably pick which control paths are or are not used. – Peter Apr 19 '19 at 06:36
6

It's not mandatory to have a return statement in a function declared as returning non-void and it doesn't have to lead to undefined behaviour.

Such a function could:

  • Not return, say by entering an infinite loop
  • Return by throwing an exception
  • Call a function that itself does not return, such as std::terminate

Of course, if a function avoids undefined behaviour by always doing one of the above it probably shouldn't be declared as returning non-void if possible.

One obvious case where it would need to is if it is a virtual function which for a particular point in a class hierarchy can't return a valid value and always exits via an exception.

CB Bailey
  • 755,051
  • 104
  • 632
  • 656
4

Yes, it must return a value.

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.

This question will bring more light to the subject

Community
  • 1
  • 1
Tom
  • 43,810
  • 29
  • 138
  • 169
  • Thank you so much. I see it as a philosophical minutia now. By "must", the standard means "must, or unknown behavior will ensue." – AlwaysLearning May 06 '10 at 20:19
1

Is it mandatory? I don't believe so, however not returning a value in a non-void returning function is undefined as per my understanding of the c++ standards (except for main, which returns 0).

Does that mean it's OK? Probably not - if the function is supposed to return a value, you should be returning one, that could get real messy in complex code bases.

cmjreyes
  • 246
  • 4
  • 12
1

Forgetting to include a return statement in some control path of a value-returning function does not make your code ill-formed. I.e. you should normally expect the code to compile (maybe with a warning). In that sense it is not "mandatory".

However, actually flowing off the end of value-returning function in C++ is always undefined behavior. (In C it is undefined behavior only if the calling code actually uses the result.)

AnT stands with Russia
  • 312,472
  • 42
  • 525
  • 765
  • The C++ standards allow control to leave `main()` without a `return` statement - the behaviour is perfectly well defined in that case. – Peter Apr 19 '19 at 06:30
0

Like the GMan said the only exception is the main function. I still see tons of books returning 0 in main which isn't really necessary. Oh well I guess it could be worse and you could be learning from a book that uses void main() instead of int main(). But I think what you should learn from all this is that your compiler is complaining for a reason and it's good you took note of it since it will usually save you headaches in the long run.

daveangel
  • 573
  • 2
  • 6