4

My C++ code looks like this:

int f(int i){
    if (i > 0) return 1;
    if (i == 0) return 0;
    if (i < 0) return -1;
}

It's working but I still get:

Warning: No return, in function returning non-void

Even though it is obvious that all cases are covered. Is there any way to handle this in "proper" way?

user31027
  • 185
  • 2
  • 13
  • 1
    http://www.tutorialspoint.com/cplusplus/cpp_if_else_statement.htm What you'll want to do is restructure this to an if/else if/else statement – user2366842 Jan 28 '16 at 14:05
  • There are numerous duplicates of this question, including: http://stackoverflow.com/questions/204476/what-should-main-return-in-c-and-c – HelloWorld Jan 28 '16 at 14:05
  • 1
    `Even though it is obvious that all cases are covered` I think, it's not that simple in general. Even more, i suspect this is undecidable. – arrowd Jan 28 '16 at 14:05
  • 1
    It's a warning, not an error. Warnings are things that the compiler thinks you might care about. – Kerrek SB Jan 28 '16 at 14:06
  • You can add a `return` statement after all the `if` statements, and that will probably silence this warning. And as an added bonus, after you do that, if you change to a different compiler you'll get a warning about unreachable code. – Pete Becker Jan 28 '16 at 14:14

4 Answers4

9

The compiler doesn't grasp that the if conditions cover all possible conditions. Therefore, it thinks the execution flow can still fall through past all ifs.

Because either of these conditions assume the others to be false, you can write it like this:

int f(int i) {
    if (i > 0) return 1;
    else if (i == 0) return 0;
    else return -1;
}

And because a return statement finally terminates a function, we can shorten it to this:

int f(int i) {
    if (i > 0) return 1;
    if (i == 0) return 0;
    return -1;
}

Note the lack of the two elses.

cadaniluk
  • 14,449
  • 2
  • 34
  • 61
  • Adding `Assert(i < 0);` before the final `return` is also advised: this communicates intention to the next developer to read it (possibly you!), and (in slightly more complex situations) catches logic errors in debug, and has no performance impact on release code. – Yakk - Adam Nevraumont Jan 28 '16 at 14:55
  • @Yakk Admittedly, an `assert` would be nice but I don't deem it necessary. Except for multithreaded programs with possibly occuring race conditions, `i < 0` is true. – cadaniluk Jan 28 '16 at 15:01
  • Even in multithreaded programs `i < 0` is going to be true (`int i` is a local variable). Barring UB (someone trashing your stack). My point is that documenting what you mean with an assert is a good habit: you don't assert because the case might not be true, you assert because you believe it is going to always be true. The assert both tells people what you believe to be true on a line, *and* keeps you honest by checking it in debug. Note that without it, it takes a bit longer to work out that `-1` is the return case for `i < 0` even in this simple case: in a more complex case, moreso. – Yakk - Adam Nevraumont Jan 28 '16 at 15:04
4

Is there any way to handle this in "proper" way?

A simple fix is to get rid of the last if. Since the first two are either called or not the third case must be called if you get to it

int f(int i){
    if (i > 0) return 1;
    if (i == 0) return 0;
    return -1;
}

The reason we have to do this is that the compiler cannot guarantee that your if statements will be called in every case. Since it reaches the end of the function and it might not have executed any of the if statements it issues the warning.

NathanOliver
  • 150,499
  • 26
  • 240
  • 331
0

Just help the compiler to understand your code. Rewrite the function the following way

int f(int i){
    if (i > 0) return 1;
    else if (i == 0) return 0;
    else return -1;
}

you could also write the function for example like

int f( int i )
{
    return i == 0 ? 0 : ( i < 0 ? -1 : 1 );
}

Another way to write the function in one line is the following

int f( int i )
{
    return ( i > 0 ) - ( i < 0 );
}
Vlad from Moscow
  • 224,104
  • 15
  • 141
  • 268
0

The compiler doesn't know that all options are covered, because in terms of your function's syntax there's nothing to suggest it.

A simplified example:

                           int f(int i)

        if                      if                   if

(int > int), return    (int == int), return   (int < int), return

A clearer structure like if/else with a return in each yields an Abstract-Syntax-Tree which clearly shows there's a return in each case. Yours, however, is dependent on the evaluation of nodes in the AST, which isn't covered in the syntax check (by which you're being issued a warning).

Beyond pure syntax, if the compiler were to rely on "possible" evaluations as well in trying to figure out the behavior of your program, it would ultimately need to entangle itself and probably hitting the halting problem. Even if it managed to cover some cases, this would probably spawn more questions from users than it would answer, and also risk an entirely new level of bugs.

Yam Marcovic
  • 7,467
  • 25
  • 37
  • Well, it should not be that hard for for a compiler to see that all options are covered. They do much more complex analysis when they optimize code. it's just no one paid attention to that. – SergeyA Jan 28 '16 at 14:19
  • @SergeyA The warning is for potentially problematic syntax. And that's what it is: just a warning. (As noted by KerrekSB) – Yam Marcovic Jan 28 '16 at 14:22
  • 1
    @There is no such thing as 'just warning'. Any sane software is compiled in 'warnings as errors' mode. – SergeyA Jan 28 '16 at 14:25
  • @SergeyA Ever heard of boost? – Yam Marcovic Jan 28 '16 at 14:26
  • Well, your sarcasm is somewhat misconstrued. Care to elaborate beyond that? – SergeyA Jan 28 '16 at 14:27
  • @SergeyA Well, it's not really sarcastic, it's just that there are many "sane" programs which, for one reason or another, ultimately compile with warnings _not_ treated as errors. The boost library is full of warnings, as one such example: https://software.intel.com/en-us/forums/intel-c-compiler/topic/280515 – Yam Marcovic Jan 28 '16 at 14:29
  • Boost is a library, and a very misfortunate one - it has to cater to multiple implementations, which often contradict themselves. This is what happens when you try to be standard library :) But it is a one-of-a-kind thing. Exactly because boost deals with this, no one else has. – SergeyA Jan 28 '16 at 14:31
  • @SergeyA Are you implying that boost is special in being a "library" (it's a set of libraries) that generates compiler warnings? – Yam Marcovic Jan 28 '16 at 14:37
  • No, I am implying that boost is a uniquely positioned as an extension of standard library. Standard libraries, in general, are allowed to invoke all kinds of compiler magic - because they are shipped with specific compiler and contain all sorts of othrewise dubious code for the same reason. Boost is a standard library, but it is not shipped with specific compiler - hence all it's troubles. – SergeyA Jan 28 '16 at 14:39
  • @SergeyA The point is that warnings are not specific to "insane" programs. Unless you consider many enterprise-level programs "insane", like AOSP for example (which I wouldn't necessarily disagree with, but it's really not a strong argument as far as I'm concerned). – Yam Marcovic Jan 28 '16 at 14:41
  • **ANY** enterprise-level program which is not compiled in 'warnings as error' mode (potentially supressing a couple of them, with an example of -Wswitch) is trully insane and is a ticking bomb. Had my dealing with those, btw. – SergeyA Jan 28 '16 at 14:44
  • @SergeyA I work with the Android Open Source Project. It generates warnings. Have an Android device at your disposal? :) – Yam Marcovic Jan 28 '16 at 14:50
  • Yes, and I hate it. The only reason why I use it is becase I hate Iphone even more so. Also, out of curiosity, can you give an example of warning and context? – SergeyA Jan 28 '16 at 14:50
  • @SergeyA Well, consider yourself warned. :) – Yam Marcovic Jan 28 '16 at 14:51
  • Out of curiosity - do you have an example of warning and context? As for warnings, I need none. I wrote an app for Un-Droid, it is plain nightmare. – SergeyA Jan 28 '16 at 14:52
  • @SergeyA Yes, but don't take my word for it. You can get the AOSP and compile, say, `bionic` or `frameworks/native` or even `frameworks/base`, and see what you get. – Yam Marcovic Jan 28 '16 at 14:54
  • No desire to do so, sorry :). But thanks for some insights. :d – SergeyA Jan 28 '16 at 14:55