20

Unlike Java, in C/C++ the following is allowed:

int* foo ()
{
  if(x)
    return p;

  // What if control reaches here?
}

This often causes crashes and it is hard to debug problems. Why doesn't the standard enforce to have a final return for non-void functions? (Compilers generate an error for a wrong return value.)

Is there a flag in GCC or MSVC to enforce this? (something like -Wunused-result)

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
iammilind
  • 68,093
  • 33
  • 169
  • 336
  • The take-away message from the below is: If you want these sorts of checks, use `-Wall` on gcc, and a high warning level (3 or 4) in Visual Studio. – T.J. Crowder Jun 07 '11 at 05:58
  • 4
    I've long desired a compiler flag that would result in all functions having `throw "LOL Y U HERE??";` at the end of them. The behavior is undefined, so anything can happen, and throwing an exception certainly qualifies as anything. Just for testing purposes; I'd be okay with them getting optimized out in release. – Dennis Zickefoose Jun 07 '11 at 06:23
  • It isn't undefined if `x` is declared `const bool x = true;`. – Bo Persson Jun 07 '11 at 07:41
  • @Dennis: IIRC, running off the end of a function is not UB unless the caller attempts to use the return value. – R.. GitHub STOP HELPING ICE Jun 07 '11 at 15:13
  • @R..: I believe that's the case in C, but C++ is more "strict" in this regard on account of how much more work is needed to construct most objects. And even in C, I imagine most developers would consider it a bug if they forget to return something from an accessible control path. – Dennis Zickefoose Jun 07 '11 at 18:42
  • 2
    Poor style and UB are distinct. – R.. GitHub STOP HELPING ICE Jun 07 '11 at 18:50

7 Answers7

14

It is not allowed (undefined behaviour). However, the standard does not require a diagnostic in this case.

The standard doesn't require the last statement to be return because of code like this:

while (true) {
  if (condition) return 0;
}

This always returns 0, but a dumb compiler cannot see it. Note that the standard does not mandate smart compilers. A return statement after the while block would be a waste which a dumb compiler would not be able to optimise out. The standard does not want to require the programmer to write waste code just to satisfy a dumb compiler.

g++ -Wall is smart enough to emit a diagnostic on my machine.

n. m. could be an AI
  • 112,515
  • 14
  • 128
  • 243
  • 4
    "Note that the standard does not mandate smart compilers." +1. – atzol Jul 29 '16 at 18:22
  • I think a better example would be something like: `int test(...) { if (...) { [compute something and return it]; } else { log_something(...); FATAL_ERROR(); }; }`. If `FATAL_ERROR()` can't return, then the end of `test()` can never be reached, but a compiler would typically have no way of knowing that. – supercat Jul 26 '18 at 20:28
  • This code causes undefined behaviour if condition is false (no forward progress) – M.M Sep 17 '20 at 03:00
  • @M.M This is not literal code. `condition` represents any expression. – n. m. could be an AI Sep 17 '20 at 06:38
13

Use the -Wall flag in GCC.

warning: control reaches end of non-void function

Or more specifically, -Wreturn-type.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Prince John Wesley
  • 62,492
  • 12
  • 87
  • 94
  • IIRC gcc only diagnoses it when optimizations are turned on, because it uses control flow analysis to diagnose it and that is not run when not optimizing. – Jan Hudec Jun 07 '11 at 05:44
  • @T.j. Crowder: `For C ++ , a function without return type always produces a diagnostic message, even when -Wno-return-type is specified. The only exceptions are main and functions defined in system headers` - From `gcc man` page – Prince John Wesley Jun 07 '11 at 05:54
  • Interesting, gcc didn't detect it with `-Wall` if I did it in `main`, branching on `argc`. But it *did* detect it if I added a separate function and did it in there. `main` would appear to be a special case (as it is in so many ways). **Edit**: @John: Overlapping comments. :-) – T.J. Crowder Jun 07 '11 at 05:56
  • @T.J. Crowder: it does only when the file is `c file` – Prince John Wesley Jun 07 '11 at 05:59
  • @John: No, it did it for me with C++ as well, provided I wasn't using a main function. – T.J. Crowder Jun 07 '11 at 06:00
  • @T.J. Crowder: in `main` function? – Prince John Wesley Jun 07 '11 at 06:01
  • @T.J. Crowder: `For c++, The only exceptions are main and functions defined in system headers`. why? – Prince John Wesley Jun 07 '11 at 06:03
  • @John: I have no idea why. :-) – T.J. Crowder Jun 07 '11 at 06:05
  • @andrewdski:`Warn whenever a function is defined with a return-type that defaults to "int". Also warn about any "return" statement with no return-value in a function whose return-type is not "void".` - from `man` page. – Prince John Wesley Jun 07 '11 at 06:06
  • Yes, sorry. I didn't delete my comment fast enough :). I managed to get confused. In any case, I think the C++ difference is only for omitting the type. I'm fairly certain the warning about reaching the end of a non-void function can be disabled in C++. – andrewdski Jun 07 '11 at 06:11
  • 3
    @T.J `main()` doesn't need to contain explicit `return` value; see from Bjarne Stroustrup website http://www2.research.att.com/~bs/bs_faq2.html#void-main – iammilind Jun 07 '11 at 06:31
  • 1
    It is defined by standard, check the Shafik's answer in [here](http://stackoverflow.com/questions/21870290/xcode-5-c-when-a-function-missing-the-return-value-the-compiler-generates-a-w?noredirect=1#comment33112361_21870290) – r0n9 Feb 19 '14 at 03:53
  • @iammilind That link is dead. Is there another source on this? – Supernormal Nov 29 '18 at 11:58
  • @Supernormal, here is the new link in his own website: http://www.stroustrup.com/bs_faq2.html#void-main – iammilind Nov 29 '18 at 12:49
  • Great. I also found that the same is true for C. Also in C, no return from main is equivalent to `return 0;`, as per the C standard, section 5.1.2.2.3 http://www.open-std.org/JTC1/SC22/WG14/www/docs/n1256.pdf – Supernormal Nov 29 '18 at 16:08
3

My guess: Because sometimes the programmer knows better than the compiler. With this simple example, it's clear that someting is wrong, but consider a switch of many values, or many checks in general. You, as the coder, know that certain values just will not be passed in to the function, but the compiler doesn't and just hints you, that there might be something wrong.

#include <iostream>

int foo(){
    if(false)
        return 5;
}

int main(){
    int i = foo();
    std::cout << i;
}

Note that even warning level 1 on MSVC gives the following warning:

warning C4715: 'foo' : not all control paths return a value

Xeo
  • 129,499
  • 52
  • 291
  • 397
  • 2
    *"Note that even warning level 1 on MSVC gives the following warning:"* That's interesting. I didn't get that even with level 4 with VS 2005. – T.J. Crowder Jun 07 '11 at 05:38
  • @T.J.: According to MSDN, 2005 should also emit that warning on level 1. See the link I added. – Xeo Jun 07 '11 at 05:46
  • @Xeo: Fascinating. I get the error if I add a `foo` function like yours, but *not* if I do exactly the same thing in the auto-generated `_tmain` function; [example](http://pastie.org/2030943). The main function is special (as in so many things). – T.J. Crowder Jun 07 '11 at 05:53
  • Control flow warnings like this are generally emitted only when the optimiser runs and does analysis. So they are normally retail-only. – Martyn Lovell Jun 07 '11 at 05:53
  • @Martyn: That's not my experience at all, with various compilers. With gcc, for instance, I just tried `-O0 -g -Wall` and still got the warning (when not testing it with `main`). – T.J. Crowder Jun 07 '11 at 06:01
  • 2
    @example: That's because the standard specifically allows `main` to be without a return statement. If it is left out, the result is as if it was `return 0;` in the end. – Xeo Jun 07 '11 at 06:06
2

You can convert the warning into an error by using the following compiler options

-Wreturn-type -Werror=return-type.

Check out This link

Avishek Bhattacharya
  • 6,534
  • 3
  • 34
  • 53
Florian
  • 81
  • 1
  • 4
1

As far as I remember, Visual Studio 2008 warns you about a "execution path that does not have a return value". It is allowed in the meaning of that "C++ won't stop you from shooting you in the foot". So you are to think, not the compiler.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Tomasz Kowalczyk
  • 10,472
  • 6
  • 52
  • 68
1

The obvious answer is: because it's not an error. It's only an error if x is false and if the caller uses the return value, neither of which can necessarily be determined by the compiler, at least in the general case.

In this particular case (returning a pointer), it wouldn't be too difficult to require a return for all paths; Java does this. In general, however, it's not reasonable in C++ to require this, since in C++, you can return user defined types for which it may be impossible to construct a value (no default constructor, etc.) So we have the situation where the programmer might not be able to provide a return in a branch that he or she knows can't be taken, and the compiler can't determine that the branch can't be taken.

Most compilers will warn in such cases, when it can determine the flow. All of the ones I've seen also warn in some cases where it's clearly impossible to fall off the end, however. (Both g++ and VC++ warn about:

int
bar( char ch )
{
    switch ( ch & 0xC0 ) {
    case 0x00:
    case 0x40:
        return 0;

    case 0x80:
        return -1;

    case 0xC0:
        return 1;
    }
}

, at least with the usual options. Although it's quite clear that this function never falls off the end.)

James Kanze
  • 150,581
  • 18
  • 184
  • 329
0

What the standard says about this kind of programming is that it produces undefined behavior.

Undefined behavior is the joy and pity of C/C++, but it is also a fundamental feature of the language design that allows for many of the low-level optimizations that make C a sort of "high level assembler" (it is not, actually, but just to give you an idea).

So, while redirecting to John's answer about the switch to use with GCC, to know "why" the standard does not prevent that, I would point to a very interesting analysis of undefined behavior and all of its misteries: What Every C Programmer Should Know About Undefined Behavior. It makes for a very instructive reading.

sergio
  • 68,819
  • 11
  • 102
  • 123