16

If a function has a return type other than void, and the function does not return anything, then I guess the compiler returns a garbage value (possibly seen as an uninitialized value). It happens at compile time, so why shouldn't it show an error?

For example,

int func1() {
    return; // error
}

int func2() {
    // does not return anything
}

The second func2 should throw an error, but it does not. Is there a reason for it? My thinking was such that, it can be seen as an uninitialized value, so if we need to throw an error in the second case, then we need to throw error, if an value is uninitialized, say

  int i;  // error
  int i = 6;  // okay

Any thoughts, or is this a duplicate question? I appreciate your help.

user207421
  • 305,947
  • 44
  • 307
  • 483
howtechstuffworks
  • 1,824
  • 4
  • 29
  • 46
  • 2
    Is it C or C++? Do you get compiler errors or warnings? Which compiler are you using? – littleadv Mar 30 '12 at 02:01
  • possible duplicate of [gcc options: warning on non-void functions without a return statement](http://stackoverflow.com/questions/9924570/gcc-options-warning-on-non-void-functions-without-a-return-statement) – Oliver Charlesworth Mar 30 '12 at 02:05
  • Well, I see the warnings, the question is kind of like, whey there is no error? why does not the compiler throw an error, despite seeing it? – howtechstuffworks Mar 30 '12 at 02:09
  • Values are returned. Compilation errors are shown, or printed. Neither of them is thrown. Exceptions are thrown. Don't misuse standard teminology. – user207421 Mar 31 '20 at 01:40

4 Answers4

23

In C++, such code has undefined behaviour:

[stmt.return]/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. ...

Most compilers will produce a warning for code similar to that in the question.

The C++ standard does not require this to be a compile time error because in the general case it would be very difficult to correctly determine whether the code actually runs off the end of the function, or if the function exits through an exception (or a longjmp or similar mechanism).

Consider

int func3() {
    func4();
}

If func4() throws, then this code is totally fine. The compiler might not be able to see the definition of func4() (because of separate compilation), and so cannot know whether it will throw or not.

Furthermore, even if the compiler can prove that func4() does not throw, it would still have to prove that func3() actually gets called before it could legitimately reject the program. Such analysis requires inspection of the entire program, which is incompatible with separate compilation, and which is not even possible in the general case.

Roddy
  • 66,617
  • 42
  • 165
  • 277
Mankarse
  • 39,818
  • 11
  • 97
  • 141
  • 3
    Many languages including C# and Java would require a `return someValue;` statement in the above example, even though it could never be executed. Language design is about tradeoffs, and the relative value of useful diagnostics versus an occasional need for silly code to appease a compiler. I disagree with many of the Java/C# decisions, but this particular one I have no qualm with. – supercat Apr 03 '15 at 22:15
  • 1
    @supercat: My answer is meant to be interpreted as: "C++ makes this undefined behaviour; but unfortunately, that is not enough for compilers to actually reject this code, because it is impossible (at compile time) to (perfectly) detect whether or not the actual undefined-behaviour occurs.". That isn't to say that it is impossible to design a different language which conservatively rejects programs that *could* be valid but which don't fit into the safety model of that language's type system (which C++ already does, for other things). – Mankarse Apr 03 '15 at 22:24
12

In C, quoting N1256 6.9.1p12:

If the } that terminates a function is reached, and the value of the function call is used by the caller, the behavior is undefined.

So it's legal (but a bad idea) for a non-void function to fail to return a value, but if it does so and the caller attempts to use the result, the behavior is undefined. Note that it doesn't necessarily just return some arbitrary value; as far as the standard is concerned, anything is possible.

Pre-ANSI C didn't have the void keyword, so the way to write a function that didn't return a value was to leave out the return type, making it implicitly return int. Requiring a return statement in a value-returning function would have broken old code. It would also have required extra analysis by the compiler to determine that all code paths hit a return statement; such analysis is reasonable for modern compilers, but might have been an excessive burden when C was first standardized.

C++ is slightly more strict. In C++:

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 the behavior is undefined whether the caller attempts to use the (nonexistent) result or not.

C and C++ compilers certainly can warn about missing return statements, or about control paths that fall off the end of a function without executing a return statement, but the respective standards do not require them to do so.

Keith Thompson
  • 254,901
  • 44
  • 429
  • 631
  • 2
    Such analysis is only reasonable in simple cases - in complex cases the compiler might not even have enough information available to know that it will always hit a `return` statement. – caf Mar 30 '12 at 02:16
  • It would be possible to require that all possible control paths execute a `return` statement; I think C# does so. For example, `{ if (1) { return 42; } else { puts("No return here"); }` would violate such a requirement, even though it's not actually possible to avoid the `return`. C and C++ just don't do that. – Keith Thompson Mar 30 '12 at 02:20
  • @Keith: It's infeasible. See Mankarse's answer. – Lightness Races in Orbit Mar 21 '15 at 16:32
  • @KeithThompson: Why C++ is strict regarding this? Is it due to the fact that both are different languages standardized by different committees or any other technical reason behind this? – Destructor Feb 27 '16 at 06:01
  • 1
    @PravasiMeet: C had to maintain compatibility for pre-ANSI programs. The design of C++ didn't have the same constraints. – Keith Thompson Feb 27 '16 at 09:37
6

In C, it is actually legal for a non-void function to finish without returning a value, as long as the calling code doesn't try to use the return value.

On the other hand a return statement without an expression is not allowed to appear in a non-void function.

The relevant parts of the C99 standard are §6.9.1 for the first case:

If the } that terminates a function is reached, and the value of the function call is used by the caller, the behavior is undefined.

and §6.8.6.4 for the second case:

A return statement without an expression shall only appear in a function whose return type is void.

caf
  • 233,326
  • 40
  • 323
  • 462
2

Both of your functions are ill formed. The difference between them is that your func1 violates the rules about how the return statement can be used while your func2 is undefined behavior. The return statement in your func1 is illegal and an implementation must diagnose this. The lack of a return statement in your func2 is undefined behavior. Most compilers will diagnose this, but none have to.

David Hammen
  • 32,454
  • 9
  • 60
  • 108
  • In C, the first function is not ill-formed. The behaviour is only undefined if the caller actually tries to use the return value. – caf Mar 30 '12 at 02:15
  • Yeah, I agree, this is more of a test and trying to find out why the C commite have this way... – howtechstuffworks Mar 30 '12 at 02:15